给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号子串的长度。
* 思考:首先我们要知道如何判断一个括号子串是有效的,方法就是在这一串子串里面首先找出至少一对左右括号且中间没有任何字符 * 比如 (()(())) ,我们可以找到两对括号,分别消去这两对括号之后剩下 (()) ,然后再进行两次消除便可以证明这是一对有效的括号子串 * 那么已知任何一对有效的括号子串,都是从一个 ()开始消除,无论以怎样的顺序消除,组成这一对对消除了的括号的左右字符组合总是相同的 * 举个例子:一对有效的括号子串长度为2n 那么总是有两个数组 left[] 和right[] 有,如果对这个括号字符串进行任意消除有 left[m]和right[n] * 是一对,那么不管进行怎么消除,都会是 left[m]和right[n]作为一对消除掉 * 由上我们知道,如果以 chars[i-1]结尾的有效括号子串str[i-1]长度为dp[i-1] 且这对子串左边字符为'(' 右边字符为 ')',那么就有以chars[i]为结尾并且长度 * 为dp[i-1]+2。 且在这个子串内,有且只有一个'('字符可以和 chars[i]相组合 就是str[i-1]左边这个'(' * 考虑到以上我们还要知道,两个有效括号子串连接起来也一定是有效子串,所以我们在 chars[i] == ')' 且 chars[i + 1 - (dp[i - 1] + 2)]=='(' * 那么 i + 1 - (dp[i - 1] + 2) 到 i之间的子串一定是有效子串且长度为dp[i-1]+2,在生成这一对有效子串之后如果前面也有有效子串存在的话,由 * i往前形成的最长有效子串还要再加上之前的长度 * 所以动态转移议程为 dp[i] = dp[i - 1] + 2 + dp[i + 1 - (dp[i - 1] + 2) - 1] ^ {chars[i] == ')' &&'(' == chars[i + 1 - (dp[i - 1] + 2)] * && i + 1 - (dp[i - 1] + 2) - 1 >= 0}
代码如下:
public int longestValidParentheses(String s) { //让dp【i】表示以i结点结束的能够形成的最长子串的长度 int[] dp = new int[s.length()]; char[] chars = s.toCharArray(); int max = 0; for (int i = 0; i < chars.length; i++) { if (i == 0) { dp[i] = 0; } else { //dp[i]=dp[i-1]+2 + dp[ i+1 - (dp[i-1]+2)-1] ^ chars[i]==chars[ i+1 - (dp[i-1]+2)] if (chars[i] == ')' && i + 1 - (dp[i - 1] + 2) >= 0 && '(' == chars[i + 1 - (dp[i - 1] + 2)]) { if (i + 1 - (dp[i - 1] + 2) - 1 >= 0) { dp[i] = dp[i - 1] + 2 + dp[i + 1 - (dp[i - 1] + 2) - 1]; } else { dp[i] = dp[i - 1] + 2; } } } //每次把最大值记录下来,最后输出 max = Math.max(max, dp[i]); } return max; }
顺利通过
复杂度分析:
时间复杂度: O(n) 空间复杂度 O(n)
方法2:栈
括号问题我们很容易想到栈,我们可以从左向右遍历字符串,如果是'(',则入栈,如果是')',且当前栈顶为'(',那么就把当前栈顶字符‘(’出栈,这里为了方便的计算最大有效字符串的长度,我们把字符的index入栈,这样比较下标就可以判断消去的有效字符串的长度
public int longestValidParentheses(String s) { Stack<Integer> stack = new Stack<>(); int max = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if(c=='('){ //如果是‘(’ 入栈, stack.push(i); }else{ //如果栈顶为‘(’,则把栈顶出栈 if(!stack.isEmpty() && s.charAt(stack.peek()) == '('){ stack.pop(); //计算长度的时候要注意栈为空的情况 max = Math.max(max,i-peekIfExist(stack)); }else{ stack.push(i); } } } return max; } public int peekIfExist(Stack<Integer> stack){ return stack.isEmpty()?-1:stack.peek(); }