Skip to content

32. 最长有效括号

题目描述

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

 

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"

示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"

示例 3:

输入:s = ""
输出:0

 

提示:

  • 0 <= s.length <= 3 * 104
  • s[i]'('')'

方法一:动态规划

我们定义 f[i] 表示以 s[i1] 结尾的最长有效括号的长度,那么答案就是 maxi=1nf[i]

  • 如果 s[i1] 是左括号,那么以 s[i1] 结尾的最长有效括号的长度一定为 0,因此 f[i]=0
  • 如果 s[i1] 是右括号,有以下两种情况:
    • 如果 s[i2] 是左括号,那么以 s[i1] 结尾的最长有效括号的长度为 f[i2]+2
    • 如果 s[i2] 是右括号,那么以 s[i1] 结尾的最长有效括号的长度为 f[i1]+2,但是还需要考虑 s[if[i1]2] 是否是左括号,如果是左括号,那么以 s[i1] 结尾的最长有效括号的长度为 f[i1]+2+f[if[i1]2]

因此,我们可以得到状态转移方程:

{f[i]=0,if s[i1]=(,f[i]=f[i2]+2,if s[i1]=) and s[i2]=(,f[i]=f[i1]+2+f[if[i1]2],if s[i1]=) and s[i2]=) and s[if[i1]2]=(,

最后返回 maxi=1nf[i] 即可。

时间复杂度 O(n),空间复杂度 O(n)。其中 n 为字符串的长度。

java
class Solution {
    public int longestValidParentheses(String s) {
        int n = s.length();
        int[] f = new int[n + 1];
        int ans = 0;
        for (int i = 2; i <= n; ++i) {
            if (s.charAt(i - 1) == ')') {
                if (s.charAt(i - 2) == '(') {
                    f[i] = f[i - 2] + 2;
                } else {
                    int j = i - f[i - 1] - 1;
                    if (j > 0 && s.charAt(j - 1) == '(') {
                        f[i] = f[i - 1] + 2 + f[j - 1];
                    }
                }
                ans = Math.max(ans, f[i]);
            }
        }
        return ans;
    }
}
cpp
class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.size();
        int f[n + 1];
        memset(f, 0, sizeof(f));
        for (int i = 2; i <= n; ++i) {
            if (s[i - 1] == ')') {
                if (s[i - 2] == '(') {
                    f[i] = f[i - 2] + 2;
                } else {
                    int j = i - f[i - 1] - 1;
                    if (j && s[j - 1] == '(') {
                        f[i] = f[i - 1] + 2 + f[j - 1];
                    }
                }
            }
        }
        return *max_element(f, f + n + 1);
    }
};
ts
function longestValidParentheses(s: string): number {
    const n = s.length;
    const f: number[] = new Array(n + 1).fill(0);
    for (let i = 2; i <= n; ++i) {
        if (s[i - 1] === ')') {
            if (s[i - 2] === '(') {
                f[i] = f[i - 2] + 2;
            } else {
                const j = i - f[i - 1] - 1;
                if (j && s[j - 1] === '(') {
                    f[i] = f[i - 1] + 2 + f[j - 1];
                }
            }
        }
    }
    return Math.max(...f);
}
python
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n = len(s)
        f = [0] * (n + 1)
        for i, c in enumerate(s, 1):
            if c == ")":
                if i > 1 and s[i - 2] == "(":
                    f[i] = f[i - 2] + 2
                else:
                    j = i - f[i - 1] - 1
                    if j and s[j - 1] == "(":
                        f[i] = f[i - 1] + 2 + f[j - 1]
        return max(f)

方法二:使用栈

  • 使用栈来存储左括号的索引,栈底元素初始化为 -1,用于辅助计算有效括号的长度。
  • 遍历字符串,对于每个字符:
    • 如果是左括号,将当前位置压入栈。
    • 如果是右括号,弹出栈顶元素表示匹配了一个左括号。
      • 如果栈为空,说明当前右括号无法匹配,将当前位置压入栈作为新的起点。
      • 如果栈不为空,计算当前有效括号子串的长度,更新最大长度。
  • 最终返回最大长度。

总结:这个算法的关键在于维护一个线,栈内存放的是左括号的索引,通过弹出和压入的操作来更新有效括号子串的长度。

时间复杂度 O(n),空间复杂度 O(n)。其中 n 为字符串的长度。

ts
function longestValidParentheses(s: string): number {
    let max_length: number = 0;
    const stack: number[] = [-1];
    for (let i = 0; i < s.length; i++) {
        if (s.charAt(i) == '(') {
            stack.push(i);
        } else {
            stack.pop();

            if (stack.length === 0) {
                stack.push(i);
            } else {
                max_length = Math.max(max_length, i - stack[stack.length - 1]);
            }
        }
    }

    return max_length;
}
python
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack = [-1]
        ans = 0
        for i in range(len(s)):
            if s[i] == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    ans = max(ans, i - stack[-1])
        return ans

Released under the MIT License.