[LeetCode] 32 Longest Valid Parentheses (栈 or DP)

题意:

给你一个括号序列,求其中最长的合法括号序列的长度。

思路:

这个题的核心思路,其实是合法括号序列的定义。

合法括号的定义如下:

  1. "()" 是一个合法括号序列;
  2. 如果 "|" 表示一个合法序列,那么 "(|)" 也是一个合法序列;
  3. 如果 "|" 表示一个合法序列,那么 "||" 也是一个合法序列。

一个简单思路是,枚举所有序列,然后判断这个序列是否是合法序列。判断方法是:对于一个序列,可以根据定义递归判断是否符合上面三条之一。如果用记忆化搜索,最多需要计算 O(N^2) 次判断过程,然后枚举也是 O(N^2) 次。所以这种思路的整体时间复杂度是 O(N^2)。但是这个题 O(N^2) 会 TLE。

根据括号匹配栈的特性,可以维护每一段合法括号的长度,最后找最大的一段合法括号序列。

根据定义,我们可以按下面方式来求出一个合法括号序列:

  1. 定义一个栈,来维护括号序列;
  2. 如果遇到 "(" 则直接入栈;
  3. 如果遇到 ")":
    1. 如果栈顶是 "(",则 "(" 出栈,入栈 "()" 的合法序列;
    2. 如果栈顶两个元素形如 "(" + "|",则出栈这两个元素,入栈 "(|)";
    3. 合并栈顶的连续合法序列
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 字符的最长合法序列的长度。根据定义可以得到以下递推关系:

  1. 若第 i 个字符是 "(",则 dp[i] = 0;
  2. 若第 i 个字符是 ")",则:
    1. 若第 i-1 个字符是 "(" 则 dp[i] 为 "()" 的长度加它前面一段的最长合法长度(定义3);
    2. 若 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)
posted @ 2020-08-23 12:22  Phantom01  阅读(183)  评论(0编辑  收藏  举报