[LeetCode] 32 Longest Valid Parentheses (栈 or DP)
题意:
给你一个括号序列,求其中最长的合法括号序列的长度。
思路:
这个题的核心思路,其实是合法括号序列的定义。
合法括号的定义如下:
- "()" 是一个合法括号序列;
- 如果 "|" 表示一个合法序列,那么 "(|)" 也是一个合法序列;
- 如果 "|" 表示一个合法序列,那么 "||" 也是一个合法序列。
一个简单思路是,枚举所有序列,然后判断这个序列是否是合法序列。判断方法是:对于一个序列,可以根据定义递归判断是否符合上面三条之一。如果用记忆化搜索,最多需要计算 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)