题目:给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
解析:有效的括号子串可以分为两种,一种是()(),一种是((())),针对这两种括号的任意组合,我们可以求出状态转移方程如下,从而用一个一维数组就可以解决
1.初始化子串只有0和1的情况,当只有s[0]等于"("和s[1]等于")"时,dp[0]=0,dp[1]=2,其余情况dp[0]和dp[1]都为0
2.从下标2开始遍历字符串:
(1)如果s[i]="("时,无法判断出长度,因此dp[i]=0,
(2)当s[i]=")"时,
如果s[i-1]="(",则是()()的情况,我们可以用dp[i]=dp[i-2]+2来表示;
如果s[i-1]=")"时则比较复杂,首先我们需要向前滑动s[i-1]的合法子串距离dp[i-1],去找跟下标i对应的i-1-dp[i-1]是否存在(用大于零判断),如果不存在则dp[i] = 0,如果还存在且s[i-1-dp[i-1]]等于"(",再考虑到前面相连的字符串有括号闭合的情况,需要把前面相连的已经闭合的括号的子串都相加,再去判断i-1-dp[i-1]下标前一个位置是否还存在,如果还存在则把dp[i-2-dp[i-1]]+dp[i-1]+2,如果不存在则dp[i-1]+2
我们模拟一遍,如下图,先是初始化,初始化完毕后,当程序走到下标3时,因为前一个s[2]等于“(",因此dp[下标3]=dp[下标1]+2等于4,dp[下标6]同理等于dp[下标4]+2等于2,当程序走到下标7时,下标6为")",又已知dp[6]等于2,因此我们需要向前滑动dp[6]的合法子串距离,即i-1-dp[6]的位置下标4的下标是否还存在且s[4]是否等于"(",如果等于“(",因为很有可能前面相连的字符串有括号闭合的情况,比如下面这种,需要把前面相连的已经闭合的括号的连续子串都相加,再去判断在i-1-dp[6]的前一个位置即i-2-dp[6]即下标3是否还存在,如果还存在则把dp[3]+dp[6]+2即dp[i-2-dp[i-1]]+dp[i-1]+2等于8,而下标8则是i-1-dp[7]即下标-1不存在dp[8]=0
( | ) | ( | ) | ( | ( | ) | ) | ) |
0 | 2 | 0 | 4 | 0 | 0 | 2 | 8 | 0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
代码如下:
public class Solution32 {
public int longestValidParentheses(String s) {
int dp[] = new int[s.length()];
if (s.length() < 2)
return 0;
if (s.charAt(0)=='('&&s.charAt(1)==')'){
dp[0] = 0;
dp[1] = 2;
}else{
dp[0] = 0;
dp[1] = 0;
}
for(int i = 2;i<s.length();i++){
if (s.charAt(i)=='(')
dp[i] = 0;
else{
if (s.charAt(i-1)=='(')
dp[i]= dp[i-2]+2;
else{
if (i-1-dp[i-1]>=0&&s.charAt(i-1-dp[i-1])=='('){
if (i-2-dp[i-1]>0)
dp[i] = dp[i-2-dp[i-1]]+dp[i-1]+2;
else
dp[i] = dp[i-1]+2;
}
}
}
}
return max(dp);
}
private int max(int[] dp) {
int max = 0;
for (int i = 0;i<dp.length;i++){
if (max<dp[i])
max = dp[i];
}
return max;
}
}