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

一、栈+boolean[]
遍历数组,记录能匹配的括号对在boolean[]中,能否匹配通过栈;
最后遍历boolean[]计算连续最大长度

    public int longestValidParentheses(String s) {
        Stack<Integer> stack = new Stack<>();
        boolean[] hit = new boolean[s.length()];
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                if (stack.isEmpty()) {
                    continue;
                }
                Integer index = stack.pop();
                hit[index] = true;
                hit[i] = true;
            }
        }
        return getMaxContinuousStr(hit);
    }

    // 数数连续true的最大长度
    private int getMaxContinuousStr(boolean[] hit) {
        int maxLen = 0, count = 0;
        for (int i = 0; i < hit.length; i++) {
            if (hit[i]) {
                count++;
            } else {
                if (count > maxLen) {
                    maxLen = count;
                }
                count = 0;
            }
        }
        return Math.max(maxLen, count);
    }

二、纯栈
难点在于,出栈的时候,怎么判断和记录这个连续长度

    public int longestValidParentheses(String s) {
        Stack<Integer> st = new Stack<Integer>();
        int ans = 0;
        int start = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                st.add(i);
            } else {
                if (!st.isEmpty()) {
                    st.pop();
                    if (st.isEmpty()) { // 连续的情况,回退到第一个
                        ans = Math.max(ans, i - start + 1);
                    } else { // stack有值的情况,距离 = 当前点 - (最近未匹配左括号+1)
                        ans = Math.max(ans, i - (st.peek() + 1) + 1);
                    }
                } else { // 不连续,断掉,重置新的start
                    start = i + 1;
                }
            }
        }
        return ans;
    }

三、纯栈+push右括号
在栈空的时候,压入右括号的神来之笔,把出栈的代码统一了;代码更简洁,但是这个思路的想到,和理解要比二难一些

    public int longestValidParentheses(String s) {
        int maxAns = 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                stack.pop();
                if (stack.isEmpty()) {
                    stack.push(i);
                } else {
                    maxAns = Math.max(maxAns, i - stack.peek());
                }
            }
        }
        return maxAns;
    }

四、动态规划dp版本
初始化dp数组为0。
遍历字符串s的每个字符,从第二个字符开始。
如果当前字符是'(',则dp[i]可忽略,因为以'('结尾的子串一定不是有效括号子串。
如果当前字符是')',

  • 如果前一个字符是'(',则可以构成一个有效括号子串,此时dp[i]的值为dp[i-2]+2,表示以第i个字符结尾的最长有效括号子串的长度。
  • 如果前一个字符是')',则需要判断前一个字符对应的最长有效括号子串的起始位置的前一个字符是否是'(',如果是,则可以构成一个有效括号子串,此时dp[i]的值为dp[i-1]+dp[i-dp[i-1]-2]+2,表示以第i个字符结尾的最长有效括号子串的长度。

在遍历过程中,我们需要记录最长的有效括号子串的长度,即maxLength。

    public int longestValidParentheses(String s) {
        int maxLength = 0;
        int[] dp = new int[s.length()];
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
                } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                }
                maxLength = Math.max(maxLength, dp[i]);
            }
        }
        return maxLength;
    }

lindsay_bubble
26 声望11 粉丝