动态规划----10.最长有效括号

32. 最长有效括号 - 力扣(LeetCode)

/**

validLen[]:有效长度,validLen[i]代表,以下标i结尾时连续有效括号长度

初始时全部默认初始化为0,且i = 0时,必定不存在有效括号,从1开始

动态规划:

情况一:()()

以下标1结尾:validLen[1]--> if(s[1] == ')') --> if(s[1 - 1] == '(') --> validLen[1] == 2

以下标2结尾:validLen[2]--> if(s[2] == ')') --> if(s[2 - 1] == '(') --> validLen[2] == 2 (长度为3最多就一个括号)

以下标3结尾:validLen[3]--> if(s[3] == ')') --> if(s[3 - 1] == '(') --> validLen[3] == 2 + validLen[3 - 2]

.......

以下标i结尾:validLen[i]--> if(s[i] == ')') --> if(s[i - 1] == '(') --> validLen[i] == 2 + validLen[i - 2]

即,当前[i-1,i]-->[(,)]可组成一个有效括号长度为2,还要加上以i - 2结尾的有效括号长度(注,当i >= 3时才成立,只有长度为4时才有可能存在两对及以上括号)

情况二:(())

以下标i结尾:validLen[i]--> if(s[i] == ')') --> if(s[i - 1] == ')') --> if(s[i - validLen[i - 1] - 1] == '('])

--> validLen[i] = 2 + validLen[i - 1] + validLen[i - validLen[i - 1] - 2]

即最外层的(2) + 中间嵌套的(validLen[i - 1]) + 最外层左边有可能的(validLen[i - validLen[i - 1] - 2])

栈:

定义一个布尔数组Marks记录括号是否合法,与一个栈

遍历字符串,如果遇到左括号则压入栈中(下标),如果遇到右括号则弹出元素

将弹出的元素与当前遍历到的元素对应下标在Marks设置为true,若无元素可弹出,则将Marks对应位置设置为false

遍历布尔数组,最长连续的true即为最长连续有效括号

*/

java 复制代码
class Solution {
    /**
        validLen[]:有效长度,validLen[i]代表,以下标i结尾时连续有效括号长度
        初始时全部默认初始化为0,且i = 0时,必定不存在有效括号,从1开始
        
    动态规划:
        情况一:()()
            以下标1结尾:validLen[1]--> if(s[1] == ')') --> if(s[1 - 1] == '(') --> validLen[1] == 2
            以下标2结尾:validLen[2]--> if(s[2] == ')') --> if(s[2 - 1] == '(') --> validLen[2] == 2 (长度为3最多就一个括号)
            以下标3结尾:validLen[3]--> if(s[3] == ')') --> if(s[3 - 1] == '(') --> validLen[3] == 2 + validLen[3 - 2]
            .......
            以下标i结尾:validLen[i]--> if(s[i] == ')') --> if(s[i - 1] == '(') --> validLen[i] == 2 + validLen[i - 2]
            即,当前[i-1,i]-->[(,)]可组成一个有效括号长度为2,还要加上以i - 2结尾的有效括号长度(注,当i >= 3时才成立,只有长度为4时才有可能存在两对及以上括号)

        情况二:(())
            以下标i结尾:validLen[i]--> if(s[i] == ')') --> if(s[i - 1] == ')') --> if(s[i - validLen[i - 1] - 1] == '(']) 
            --> validLen[i] = 2 + validLen[i - 1] + validLen[i - validLen[i - 1] - 2] 
            即最外层的(2) + 中间嵌套的(validLen[i - 1]) + 最外层左边有可能的(validLen[i - validLen[i - 1] - 2])
    
    栈:
        定义一个布尔数组Marks记录括号是否合法,与一个栈
        遍历字符串,如果遇到左括号则压入栈中(下标),如果遇到右括号则弹出元素
        将弹出的元素与当前遍历到的元素对应下标在Marks设置为true,若无元素可弹出,则将Marks对应位置设置为false
        遍历布尔数组,最长连续的true即为最长连续有效括号
    */
    public int longestValidParentheses(String s) { 
        //动态规划
        //return DP(s);

        //栈
        return byStack(s);
    }

    //栈
    private int byStack(String s) {
        //记录括号是否合法
        boolean marks[] = new boolean[s.length()];

        //双端队列模拟栈
        Deque<Integer> stack = new ArrayDeque<>();

        char c[] = s.toCharArray();
        for(int i = 0; i < c.length; i++) {
            //左括号入栈
            if(c[i] == '(') { 
                stack.push(i);
            } 
            
            //右括号弹出栈顶元素
            else {
                if(!stack.isEmpty()) { //marks默认初始化为false,为空不用处理
                    int index = stack.pop();
                    marks[index] = true;
                    marks[i] = true;
                }
            }
        }

        //遍历marks,得出最长连续括号
        int maxLen = 0;
        int temp = 0;
        for(int i = 0; i < marks.length; i++) {
            if(marks[i]) {
                temp++;
                maxLen = Math.max(maxLen,temp);
            } else {
                temp = 0;
            }
        }

        return maxLen;
    }

    //动态规划
    private int DP(String s) {
        //默认初始化全为0
        int validLen[] = new int[s.length()];

        //遍历过程中迭代最长有效值
        int maxLen = 0;

        //以0结尾不可能存在有效括号,从1开始即可
        for(int i = 1; i < s.length(); i++) {
            if(s.charAt(i) == ')') {
                if(s.charAt(i - 1) == '(') {
                    if(i >= 3) { //长度大于等于4才可能出现两对及以上有效括号
                        validLen[i] = 2 + validLen[i - 2];
                    } else { //长度小于4,最多一对有效括号
                        validLen[i] = 2;
                    }
                } 
                
                //情况二 嵌套
                else if(s.charAt(i - 1) == ')') {
                    //中间嵌套了n个括号,与最外层匹配的只能在i - validLen[i - 1] - 1处;validLen[i - 1]代表嵌套的n个括号的长度
                    if(i - validLen[i - 1] - 1 >= 0 && s.charAt(i - validLen[i - 1] - 1)== '(') {
                        //外层 + 中间嵌套的
                        validLen[i] = 2 + validLen[i - 1];

                        //若整体左侧还有有效括号,还需要加上左侧的 例:()()((()))
                        if(i - validLen[i - 1] - 2 >= 0) {
                            validLen[i] += validLen[i - validLen[i - 1] - 2];//i - validLen[i - 1] - 1(嵌套结构整体) 再 - 1,嵌套结构整体左侧
                        }
                    }
                }
            }
            maxLen = Math.max(maxLen,validLen[i]);
        }

        return maxLen;
    }
}