32. 最长有效括号

17 阅读2分钟

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

示例 1:

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

示例 2:

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

示例 3:

输入: s = ""
输出: 0

题解:

/**
 * @param {string} s
 * @return {number}
 */
// 方法一:栈
var longestValidParentheses = function (s) {
    let len = 0;
    const stack = [];
    // 栈内预设初始值
    stack.push(-1)
    for (let i = 0; i < s.length; i++) {
        let val = s[i]
        // 当遇到左括号是入栈下标
        if (val == '(') {
            stack.push(i)
        } else {
            // 当遇到右括号是入栈下标
            stack.pop()
            // 判断当栈不为空时 取当前下标与栈顶元素差值为有效长度
            // 当栈顶为空时当前位置入栈
            if (stack.length) {
                let cur = i - stack[stack.length - 1]
                len = Math.max(len, cur)
            } else {
                stack.push(i)
            }
        }
    }
    return len
};
// 方法二:左右遍历
var longestValidParentheses = function (s) {
    let left = 0, right = 0, manLen = 0;
    // 一次从左向右遍历,一次从右向左遍历是为了互补操作
    // 从左向右遍历 当左括号大于右括号时 
    // 例如:'(()'没办法计算出来有效长度
    for (let i = 0; i < s.length; i++) {
        let val = s[i]
        if (val == '(') {
            left++
        } else {
            right++
        }
        if (left == right) {
            manLen = Math.max(manLen, 2 * left)
        } else if (right > left) { // 避免')('情况
            left = 0;
            right = 0;
        }
    }
    left = 0;
    right = 0;
    // 从右向左遍历 解决左括号大于右括号时获取有效长度
    // 同时不能处理'())'这种情况
    for (let i = s.length - 1; i >= 0; i--) {
        let val = s[i]
        if (val == '(') {
            left++
        } else {
            right++
        }
        if (left == right) {
            manLen = Math.max(manLen, 2 * left)
        } else if (left > right) {
            left = 0;
            right = 0;
        }
    }
    return manLen
}
动态规划

思路:dp[i]表示以i结尾的最长有效括号的长度,分为4种情况,看图

复杂度:时间复杂度O(n),n是字符串的长度,总共遍历1次。空间复杂度O(n),即dp数组的空间

image.png 作者:xiaochen1024

链接:leetcode.cn/problems/lo…

// 方法三:动态规划 dp
const longestValidParentheses = (s) => {
    let maxLen = 0;
    const len = s.length;
    const dp = new Array(len).fill(0);
    for (let i = 1; i < len; i++) {
        // 以')'结尾的字符才有效
        if (s[i] == ')') {
            // 如果前一个位置是'(' 则能与当前字符形成有效括号
            if (s[i - 1] == '(') {
                // 如果前2个位置还有字符串 
                if (i - 2 >= 0) {
                    //当前状态等于 当前匹配的2个字符 加上 前两个位置匹配最长字符长度
                    dp[i] = dp[i - 2] + 2;
                } else {// 如果前2个位置没有字符串
                    dp[i] = 2;// 当前状态等于 当前匹配的2个字符
                }
                // 以i-1结尾的有效字符在向前看1个位置 如果是'(' 
                // 则能与当前字符形成有效括号
            } else if (s[i - dp[i - 1] - 1] == '(') {
                // 以i-1结尾的有效字符在向前看2个位置 如果>=于0
                if (i - dp[i - 1] - 2 >= 0) {
                    // 当前状态 = 
                    // 以i-1结尾的有效字符长度 + 
                    // 当前匹配2个有效括号 + 
                    // 以i - dp[i - 1] - 2结尾的有效字符长度
                    dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2];
                } else {
                    // 以i-1结尾的有效字符在向前看2个位置 如果<于0
                    // 当前状态=以i-1结尾的有效字符长度 + 当前匹配2个有效括号 
                    dp[i] = dp[i - 1] + 2;
                }
            }
        }
        maxLen = Math.max(maxLen, dp[i]);
    }
    return maxLen;
};

来源:力扣(LeetCode)

链接:leetcode.cn/problems/lo…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。