给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()"
两种做法:动态规划+栈
动态规划解法
dp数组的含义:已i为结尾的最长的有效括号的长度,分情况匹配前一个或者更早的'(',构建状态转移关系,租补累加到最终的最长的长度
以'('结尾的dp数组,统统赋值为0,以')'结尾的dp数组,需要按情况分析
两种情况的分析
1. 当i-1
位置的符号是'('
:
- 这意味着当前位置
i
的')'
和前一个位置i-1
的'('
可以形成一个有效的括号对,长度为2。 - 如果
i
的索引大于或等于2(即i >= 2
),则说明当前位置前面可能有已经匹配的括号对,我们需要跳过这些括号对。 - 因此,
dp[i] = dp[i-2] + 2
,即跳过前一个'('
并加上当前的')'
和前面的括号对。
2. 当i-1
位置的符号是)
时:
- 这种情况更复杂,因为我们需要继续往前查找,看是否存在一个
'('
来和当前位置的')'
匹配。
例子如下,当i=5时,i-1=4,需要去前面(i=2)的位置继续找有没有匹配的,不能直接赋值为0
0 1 2 3 4 5
字符: ( ) ( ( ) )
当i-1符号依然为')'
时,而且i-dp[i-1]-1的位置的符号为‘(’ (也就是说第i位置的')'
能和i-dp[i-1]-1位置的'('
匹配上,只不过要跳过i前面的已经匹配完成的括号对')'
,dp转移公式为
dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2]
让我们逐步分析这段转移公式
dp[i-dp[i-1]-2]是干什么的?
是获取与i的右括号匹配的i-dp[i-1]-1位置的左括号的前面的已经计算完成的括号对
dp[i-1]就是获取i前面的已经计算完成的括号对
那dp【i-1】不会包含了dp[i-dp[i-1]-2]吗?
关键在于,当i位置字符为‘(’时,该位置dp数组元素直接设置为0,也就是说,在dp[i-dp[i-1]-2]与dp[i-1]之间多出来的‘(’括号,也就是我们用于与i位置匹配的左括号,将dp[i-dp[i-1]-2]与dp[i-1]隔断了,中间是设置过为0的
解释完成,放出完整的java代码
class Solution {
public int longestValidParentheses(String s) {
int len=s.length();
int[] dp=new int[len];
//开始计数
int maxCount=0;
for(int i=1;i<len;i++){
if(s.charAt(i)==')'){
if(s.charAt(i-1)=='('){
//需要判断当前位置是不是大于2
if(i>=2){
dp[i]=dp[i-2]+2;
}else{
//如果是开头
dp[i]=2;
}
}
else if(s.charAt(i-1)==')'){
//需要往前判断是不是左括号
if(i-dp[i-1]-1>=0){
//首先判断位置够不够
//随后判断该位置是不是左括号
if(s.charAt(i-dp[i-1]-1)=='('){
//前一个位置以及匹配的左括号的前一个位置
dp[i]=dp[i-1]+2+((i-dp[i-1]-2>0)?dp[i-dp[i-1]-2]:0);
}
}
}
}
maxCount=Math.max(maxCount,dp[i]);
}
return maxCount;
}
}
栈写法
做法:
匹配过程
- 用栈
stack
来存储左括号'('
的下标。当遇到右括号')'
时,从栈中弹出一个左括号的下标进行匹配。如果能弹出,则说明当前这一对括号是有效的。
标记匹配的括号:
- 当匹配成功时,在一个数组
tmp
中标记当前左右括号为匹配位置。具体来说,当匹配时,将当前右括号和对应左括号的tmp
数组位置设为1
,表示这两个括号是有效配对。
计算最大有效子串长度:
- 遍历
tmp
数组,统计连续的1
的个数(表示连续有效的括号对)。每次遇到1
时,累加tmpCount
,并更新count
为当前tmpCount
和最大值之间的较大者。如果遇到0
,说明有效括号子串断开,重置tmpCount
。
class Solution {
public int longestValidParentheses(String s) {
//使用栈解决试试
//如果是左括号。就放入栈
//如果是右括号,尝试从栈中弹出左括号
//如果可以弹出,子串长度+2,如果栈为空,当前统计归0,跳过当前元素
ArrayDeque<Integer> stack=new ArrayDeque<>();
int len=s.length();
int tmpCount=0;
int count=0;
int[] tmp=new int[len];
for(int i=0;i<len;i++){
if(s.charAt(i)=='('){
stack.push(i);
}
else{
if(!stack.isEmpty()){
//如果不是空的
int j=stack.pop();
tmp[i]=1;
tmp[j]=1;
}
}
}
for(int i=0;i<len;i++){
if(tmp[i]==1){
tmpCount++;
count=Math.max(count,tmpCount);
}
else{
tmpCount=0;
}
}
return count;
}
}