题目大意
给定一个由左右括号()组成的字符串,然后判断其中最长的有效括号子串长度(即左右括号可以匹配的子串)。
分析与源代码
一、时间复杂度为O(n^2)的DP算法
这道题我首先想到的是动态规划解法,设dp[i][j]为1表示s[i][j]为有效括号子串,那么会有两种情况的时候dp[i][j]为1:
第一种是dp[i+1][j-1]=1且s[i]='(',s[j]=')';
第二种是枚举k(k>=i,k<=j-1),在k处将其断开,分为s[i][k]与s[k+1][j],如果s[k]='('且s[k+1]=')'且dp[i][k]与dp[k+1][j]为1;
这样每次对dp[i][j]赋值为1的时候考虑一次最大值更新即可。
这种算法的思路比较简单,但是在leetcode评测时会超时几组数据,所以需要采用下面的方法。
public int longestValidParentheses(String s) {
if(s == "") {
return 0;
}
int len = s.length(), maxm = 0;
boolean dp[][] = new boolean[len + 5][len + 5];
for(int i = 0; i < len; i++) {
dp[i][i] = false;
if(i < len - 1) {
if(s.charAt(i) == '(' && s.charAt(i + 1) == ')') {
dp[i][i + 1] = true;
maxm = 2;
continue;
}
}
}
for(int d = 2; d <= len - 1; d++) {
for(int start = 0; start <= len - d - 1; start++) {
int end = start + d;
if(d % 2 == 0) {
dp[start][end] = false;
continue;
}
if(s.charAt(start) == '(' && s.charAt(end) == ')' && dp[start + 1][end - 1]) {
dp[start][end] = true;
maxm = Math.max(d + 1, maxm);
}
for(int i = start; i <= end - 1; i++) {
if(dp[start][i] && dp[i + 1][end] && s.charAt(i) == ')' && s.charAt(i + 1) == '(') {
dp[start][end] = true;
maxm = Math.max(d + 1, maxm);
}
}
}
}
return maxm;
}
二、时间复杂度为O(n)的DP算法
我们设dp[i]表示以i结尾的最长合法括号子串的长度,那么如果s[i]=')'且s[i-1]='(',那么dp[i] = dp[i - 2] + 2,如果s[i-1]=')',那么这个时候就要去考虑s[i - dp[i - 1] - 1]的情况,如果为(,那么可以构成合法括号子串,接下来就需要考虑加上dp[i - dp[i-1]-2],因为这里会把这两个(以s[i]结尾与以s[i - dp[i - 1] - 2]结尾)子串组成一个合法括号子串。
public static int longestValidParentheses(String s) {
if(s == "") {
return 0;
}
int len = s.length(), maxm = 0;
int dp[] = new int[len + 5];
for(int i = 1; i < len; i++) {
if(s.charAt(i) == ')') {
if(s.charAt(i) == '(') {
dp[i] = dp[i - 2] + 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;
}
maxm = Math.max(maxm, dp[i]);
}
}
return maxm;
}