最长有效括号(leetcode32)

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

示例:

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

 

解析:

方法一:动态规则

我们定义dp[i] 表示以下标 i 结尾的最长有效括号的长度。

将dp数组全初始化为0.

显然,有效的子串一定以 ) 结尾,因此我们可以知道以  ( 对应的dp一定为0。

我们只需要求 ) 在dp数组中对应位置的值。

我们从前往后遍历字符串求解dp值,我们每两个字符检查一次:

1. s [ i ] = ')' 且 s[ i-1 ] = '(' ,也就是形如 “...()”, 可推断出: dp [ i ] = dp[ i-2 ] + 2 

  我们可以理解,因为结束部分的  () 是一个有效字符串,并且将之前的有效字符串的长度增加了 2 。

2.  s [ i ] = ')' 且 s[ i-1 ] = ')' , 即形如 “...))” , 可以推断出:

如果 s [ i-dp[i-1] -1 ] = '(' , 那么 dp[ i ] = dp[ i-1 ]  + dp[ i - dp[i-1] - 2] + 2

  我们可以理解,dp[i-1] 表示 i-1 位置的有效长度, i - dp[i-1] -1 表示跟 i 减去有效长度后前一个位置的字符与 i 相比是否是有效的,即是否为 ( 。

如果是,则表示 i 位置也有效,则 i 位置的有效长度 为 i-1位置的有效长度(dp[i-1]) + 2,然后再加上,这些有效位置的前一个位置的有效长度,

即 dp [ i-dp[ i-1 ] -2 ] 。

如下图

 

代码如下:

public class leetcode32 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String s = ")()())";
        System.out.println(longestValidParentheses(s));
    }

    //动态规划
    public static int longestValidParentheses(String s) {
        
        int maxans = 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;
                }
            }
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }
}

 

方法二:栈

具体做法是我们始终保持栈底元素为当前已经遍历过的元素中「最后一个没有被匹配的右括号的下标」,这样的做法主要是考虑了边界条件的处理,栈里其他元素维护左括号的下标:

  • 对于遇到的每个 ‘(’ ,我们将它的下标放入栈中
  • 对于遇到的每个 ‘)’ ,我们先弹出栈顶元素表示匹配了当前右括号:

如果栈为空,说明当前的右括号为没有被匹配的右括号,我们将其下标放入栈中来更新我们之前提到的「最后一个没有被匹配的右括号的下标」
如果栈不为空,当前右括号的下标减去栈顶元素即为「以该右括号为结尾的最长有效括号的长度」

我们从前往后遍历字符串并更新答案即可。

需要注意的是,如果一开始栈为空,第一个字符为左括号的时候我们会将其放入栈中,这样就不满足提及的「最后一个没有被匹配的右括号的下标」,为了保持统一,我们在一开始的时候往栈中放入一个值为 −1 的元素。

例如:( ) ) ( ( ( ) ) 

代码如下:

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

 

posted @ 2021-03-23 23:02  Vincent-yuan  阅读(218)  评论(0编辑  收藏  举报