(动态规划) LeetCode32. 最长有效括号

题目:
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"

示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

方法一:暴力法
思路:
1、对于给定字符串中每种可能的非空偶数长度子字符串,判断其是否有效
2、如果有效,更新最大长度
时间复杂度:O(n^3)
空间复杂度:O(n)

var longestValidParentheses = function(s) {
    let max = 0;
    if(!s) return 0;
    for(let i = 0, len = s.length; i < len; i++){
        for(let j = i + 2; j <= len; j += 2){
            let val = s.substring(i, j);
            if(isValid(val) && val.length > max)
                max = val.length;
        }  
    }    
    return max;
};
var isValid = function(s){
    let stack = [];

    for(let i = 0, len = s.length; i < len; i++){
        if(s[i] === '(')
            stack.push(1)
        else{
            if(!stack.length)
                return false;
            else
                stack.pop()
        }
    }
    return !stack.length
}

方法二:动态规划
思路:
有效的子字符串一定以 ‘)’ 结尾,在这种情况下
1、如果s[i - 1] === '(' && s[i] === ')',则dp[i] = dp[i - 2] + 2
2、如果s[i - 1] === ')' && s[i] === ')'
(1)如果s[i - dp[i - 1] - 1] === '(', 即如果Sub代表i-1位置上的最长有效括号,s[i - dp[i - 1] - 1] 则代表,在sub之前一个位置上的字符,如果该字符是'(',则
dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2];
dp[i - dp[i - 1] - 2]代表Sub子串之前的最长有效括号长度
时间复杂度:O(n)
空间复杂度:O(n)

var longestValidParentheses = function(s) {
    let max = 0,
        len = s.length;
    let dp = new Array(len).fill(0);
    for(let i = 1; i < len; i++){
        if(s[i] === ')'){
            if(s[i - 1] === '('){
                dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2
            }else if(i - dp[i - 1] - 1 >= 0 && s[i - dp[i - 1] - 1] === '('){
                dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 > 0 ? dp[i - dp[i - 1] - 2] : 0)
            }
            max = Math.max(max, dp[i])
        }
    }    
    return max;
};

方法三:栈
思路:
使用栈将配对的括号消除,栈中剩余的便是不能消除的,从中计算有效括号的最大长度,为了方便计算,添加哨兵;

时间复杂度:O(n)
空间复杂度:O(n)

var longestValidParentheses = function(s) {
    let max = 0,
        len = s.length;
    let stack = [-1];
    for(let i = 0; i < len; i++){
        if(s[i] === '('){
            stack.push(i)
        }else{
            stack.pop();
            if(!stack.length){
                stack.push(i)  
            }else{
                max = Math.max(max, i - stack[stack.length - 1])    
            }
        }
    }    
    return max;
};

方法四:双指针
思路:
1、定义两个指针left,right。
2、遇到'(',left++;遇到')',right++
3、如果left === right,更新最大值
4、如果right > left,left = right = 0
5、从右到左反方向遍历
时间复杂度:O(n)
空间复杂度:O(1)


var longestValidParentheses = function(s) {
    let max = 0, left = 0, right = 0, len = s.length;
    for(let i = 0; i < len; i++){
        if(s[i] === '('){
            left ++;
        }else{
            right ++;
        }
        if(left === right){
            max = Math.max(max, right * 2)
        }else if(right > left){
            left = 0;
            right = 0;
        }
    }  
    if(max === len) return max;
    left = right = 0;
    for(let i = len - 1; i >= 0; i--){
        if(s[i] === '('){
            left ++;
        }else{
            right ++;
        }
        if(left === right){
            max = Math.max(max, right * 2)
        }else if(left > right){
            left = 0;
            right = 0;
        }
    }    
    return max;
};

你可能感兴趣的:((动态规划) LeetCode32. 最长有效括号)