给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:
输入:s = ""
输出:0
- 用栈来找出所有匹配的左右括号,并用一个列表来记录匹配括号的索引。
- 于是这个列表中最长连续子序列的长度就是最长有效括号的长度。
public int longestValidParentheses(String s) {
Stack<Integer> stack = new Stack<>();
List<Integer> indexList = new LinkedList<>();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '(')
stack.push(i);
else{
if(!stack.isEmpty()){
indexList.add(stack.pop());
indexList.add(i);
}
}
}
if(indexList.size() == 0)
return 0;
//寻找列表中最长连续子序列的长度
Collections.sort(indexList);
int max = 0;
int index = 0;
while(index < indexList.size() - 1){
int count = 1;
while(index < indexList.size() - 1 && indexList.get(index) == indexList.get(index + 1) - 1){
count++;
index++;
}
max = Math.max(count, max);
index++;
}
return max;
}
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n) 栈和列表所需的额外空间
定义dp[i]
为以位置i结尾的最长有效括号的长度
- 一个单括号不可能形成有效括号,因此dp[0] = 0
- 如果1位置为右括号,0位置为左括号,那么dp[1] = 2
- 如果i位置为左括号,那么没有以这个位置结尾的有效括号,dp[i] = 0
- 如果i位置为右括号,分两种情况:
-
如果i-1位置为左括号,那么i-1位置和i位置能组成一个长度为2的有效括号,再加上以i-2位置结尾的最长有效括号的长度,即为以i位置结尾的最长有小括号的长度。
dp[i] = dp[i-2] + 2
-
如果i-1位置为右括号,那么以它结尾可能会有一定长度的有效括号,我们先越过这些位置,来到这些匹配好的有效括号前面一个位置,如果这个位置是左括号,那么
dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2]
例如:
"())(())"
,对于位置5,其前面的位置4已经有长度为2的匹配好的有效括号"()"
,并且它们前面的位置2为左括号,可以与位置5的右括号匹配,因此dp[i]肯定能在dp[i-1]的位置上加2。但如例子所示,以位置1结尾还有长度为2的有小括号,与之后的有小括号连上了,这时我们就需要把这部分有效括号的长度dp[i - dp[i - 1] - 2]也加上。
-
public int longestValidParentheses(String s) {
if(s == null || s.length() < 2)
return 0;
int[] dp = new int[s.length()];
//Base Case
dp[0] = 0;
dp[1] = s.charAt(1) == ')' && s.charAt(0) == '(' ? 2 : 0;
int max = Math.max(dp[0], dp[1]);
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 - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '('){
dp[i] = dp[i - 1] + 2;
dp[i] += i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0;
}
}
}
max = Math.max(max, dp[i]);
}
return max;
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)