[LeetCode] 32 Longest Valid Parentheses (棧 or DP)
阿新 • • 發佈:2020-08-23
題意:
給你一個括號序列,求其中最長的合法括號序列的長度。
思路:
這個題的核心思路,其實是合法括號序列的定義。
合法括號的定義如下:
- "()" 是一個合法括號序列;
- 如果 "|" 表示一個合法序列,那麼 "(|)" 也是一個合法序列;
- 如果 "|" 表示一個合法序列,那麼 "||" 也是一個合法序列。
一個簡單思路是,列舉所有序列,然後判斷這個序列是否是合法序列。判斷方法是:對於一個序列,可以根據定義遞迴判斷是否符合上面三條之一。如果用記憶化搜尋,最多需要計算 O(N^2) 次判斷過程,然後列舉也是 O(N^2) 次。所以這種思路的整體時間複雜度是 O(N^2)。但是這個題 O(N^2) 會 TLE。
棧
根據括號匹配棧的特性,可以維護每一段合法括號的長度,最後找最大的一段合法括號序列。
根據定義,我們可以按下面方式來求出一個合法括號序列:
- 定義一個棧,來維護括號序列;
- 如果遇到 "(" 則直接入棧;
- 如果遇到 ")":
- 如果棧頂是 "(",則 "(" 出棧,入棧 "()" 的合法序列;
- 如果棧頂兩個元素形如 "(" + "|",則出棧這兩個元素,入棧 "(|)";
- 合併棧頂的連續合法序列
class Solution: def longestValidParentheses(self, s: str) -> int: if not s: return 0 stack = [] for c in s: if '(' == c: stack.append(1) else: top = 0 while stack and stack[-1] % 2 == 0: top += stack.pop() if stack and stack[-1] == 1: stack.pop() top += 2 stack.append(top) else: if top: stack.append(top) stack.append(-1) rlt = 0 cur = 0 for i in stack: if i % 2 == 1: cur = 0 else: cur += i rlt = max(rlt, cur) return rlt
DP
dp 思路如下: 用 dp[i] 表示結尾為第 i 字元的最長合法序列的長度。根據定義可以得到以下遞推關係:
- 若第 i 個字元是 "(",則 dp[i] = 0;
- 若第 i 個字元是 ")",則:
- 若第 i-1 個字元是 "(" 則 dp[i] 為 "()" 的長度加它前面一段的最長合法長度(定義3);
- 若 dp[i-1] > 0 (前面是一個合法序列),則許要看這個序列前一個字元是不是 "("。(定義2)
class Solution: def longestValidParentheses(self, s: str) -> int: if not s: return 0 dp = [0 for _ in s] for idx, c in enumerate(s): if ')' == c: if idx > 0 and s[idx-1] == '(': dp[idx] = (dp[idx-2] if idx > 1 else 0) + 2 continue if (dp[idx-1] > 0) and (idx > dp[idx-1]) and (s[idx-dp[idx-1]-1] == '('): dp[idx] = dp[idx-1] + 2 if idx-dp[idx-1]-1 > 0: dp[idx] += dp[idx-dp[idx-1]-2] return max(dp)