Leetcode 32.最长有效括号
问题描述
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: ")()())" 输出: 4 解释: 最长有效括号子串为 "()()"
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/longest-valid-parentheses
思路
1、栈:
栈中保存的是字符串字符下标.
https://leetcode.com/problems/longest-valid-parentheses/discuss/14126/My-O(n)-solution-using-a-stack
-
从头到尾扫描栈,如果是“(”则压入栈。
-
如果是")",判断栈顶元素。如果栈顶元素是"(",则可以匹配,弹出栈顶。如果是“)”,则不能匹配,前一个非法,当前也非法,把当前下标入栈。
-
最后留在栈内的都是不能匹配的括号的下标。如果最后栈空,说明所有括号相互匹配,直接返回n。
-
可以匹配的字符串就在栈中这些下标中间,找到不匹配括号下标之间间隔的最大值即为最长有效括号(考虑最长括号从头开始情况)。
改进:动态计算最大长度。
栈顶表示最后无效括号的下标,当遇到"("时压栈,遇到")"时总是弹出栈,因为只有最后一个无效括号的下标有记录的必要,前面如果时左括号本来就应该弹,是右括号也没有保存下标的必要。如果从头开始的括号序列是最长,那么有先压入栈的-1计算。如果遇到栈空,说明-1已经被弹了(而不是左括号被弹),当前右括号必为多余的。
代码:
class Solution {
public int longestValidParentheses(String s) {
char[] arr = s.toCharArray();
Stack<Integer> stack=new Stack<>();
stack.push(-1);
int maxLen=0;
for (int i=0;i<arr.length;i++){
if (arr[i]=='('){
//栈中保存下标
//栈顶保存了最后一个无效括号的位置
stack.push(i);
}
else {
stack.pop();
if(stack.isEmpty()){//如果为空,说明-1已经被弹,比非法,压入栈
stack.push(i);
}
else {//每个非法右括号都被先弹了,非空要么是左括号,要么是-1,故可以更新最长值
maxLen=Math.max(maxLen,i-stack.peek());
}
}
}
return maxLen;
}
}
2、动态规划
dp表示以位置i(从1开始)结尾的括号之前最长的有效括号长度。
public int longestValidParentheses(String s) {
//所有表示位置的变量默认从1开始
int len=s.length();
if(len<2){
return 0;
}
int res=0;
//dp表示以位置i(从1开始)结尾的括号之前最长的有效括号长度
//dp[0],dp[1]必为0
int dp[]=new int[len+1];
char arr[]=s.toCharArray();
for (int i = 2; i <= len; i++) {
if(arr[i-1]=='('){
dp[i]=0;
}
else {
if(arr[i-2]=='('){
dp[i]=dp[i-2]+2;
}
else {
if(i-dp[i-1]-2>=0&&arr[i-dp[i-1]-2]=='('){
dp[i]=dp[i-dp[i-1]-2]+dp[i-1]+2;
}
else {
dp[i]=0;
}
}
}
res=Math.max(res,dp[i]);
}
return res;
}