90.最长有效括号

7 阅读2分钟

题目链接

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

解法1 辅助栈

思路

这题做过类似的,有效括号判断(LeetCode 20),当时是遇到 '(' 就入栈,遇到 ')' 就出栈匹配。

而这题需要入栈字符吗?我们要求的是有效括号的长度,需要用到索引,跟字符没有关系,所以我们应该入栈索引。

栈的目的是记录上一个没有被匹配的索引,每次 ')' 匹配完,只需要弹出一次,并用栈顶的新值计算长度。栈初始化有 -1 是为了设置一个基准,防止上来就出现 ')' 匹配。栈空说明基准失效,要重新 push 当前 i

代码

function longestValidParentheses(s: string): number {
    let result = 0;
    if (!s.length) return result;
    
    const stk = [-1];
    for (let i = 0; i < s.length; i++) {
        if (s[i] === '(') {
            stk.push(i);
        } else {
            stk.pop(); // 弹出一个 '(' 的索引 或 -1
            if (stk.length === 0) {
                // 没有未匹配的左括号了,更新基准位置
                stk.push(i);
            } else {
                // 当前合法长度是 i - stk[stk.length - 1]
                result = Math.max(result, i - stk[stk.length - 1]);
            }
        }
    }

    return result;
};

时空复杂度

时间复杂度:O(n)

空间复杂度:O(n)

解法2 动态规划

思路

状态定义: dp[i] 为以 s[i] 结尾的最长有效括号子串的长度,dp数组初始化的时候都为 0

只需要考虑当前是 ')' 的情况,第一种就是前一个刚好为 '(' ,这样匹配了一对。 而如果前一个是 ')',但和前面更早的 s[i - dp[i - 1] - 1] === '(' 配对。

代码

function longestValidParentheses(s: string): number {
    let result = 0;
    if (!s.length) return result;
    
    const dp = new Array(s.length).fill(0);
    for (let i = 1; i < s.length; i++) {
        if (s[i] === ')' && s[i - 1] === '(') {
            dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
        } else if (s[i] === ')' && s[i - 1] === ')' && s[i - dp[i - 1] - 1] === '(') {
            dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] >= 2 ? dp[i - dp[i - 1] - 2] : 0);
        }

        result = Math.max(result, dp[i]);
    }

    return result;
};

时空复杂度

时间复杂度:O(n)

空间复杂度:O(n)