Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
For "(()"
, the longest valid parentheses substring is "()"
, which has length = 2.
Another example is ")()())"
, where the longest valid parentheses substring is "()()"
, which has length = 4.
这道题是Hard模式,写了一晚上终于Accept了,好开心啊。
不过之后上网看了看别人的想法,自己还是naive了一些,该简单的地方让我弄复杂了,借鉴借鉴。我的代码如下:
PS 不过也弄清楚了LeetCode评判系统会一遍一遍的调用你的函数,所以我依赖一个类中的静态变量的话,每次都需要重置,要不会一直增加下去~
package datastru;
import java.util.Stack;
public class Solution {
public int longestValidParentheses(String s) {
if(s.length() == 0){
return 0;
}
if(s.indexOf(")") == -1){
return 0;
}
char[] ch = s.toCharArray();
boolean[] sit = new boolean[ch.length];
Stack<LeftParenthese> stack = new Stack<LeftParenthese>();
int max = 0;
int max_temp = 0;
int le = 0;
int ri = 0;
boolean flag = false;
for(char c : ch){
if(c == '('){
LeftParenthese left = new LeftParenthese();
stack.push(left);
ri = left.getIndex();
flag = true;
}else{
if(!stack.isEmpty()){
LeftParenthese left = stack.pop();
sit[left.getIndex()] = true;
}else{
max_temp = calmaxlength(sit,le,ri);
if(max_temp > max)
max = max_temp;
if(flag)
le = ri+1;
}
}
}
max_temp = calmaxlength(sit,le,ri);
if(max_temp > max)
max = max_temp;
// LeftParenthese.resetStatic();
return max;
}
public static void main(String[] args){
Solution sol = new Solution();
String str = ")()())()()(";
System.out.println(sol.longestValidParentheses(str));
}
private int calmaxlength(boolean[] sit, int le, int ri) {
// TODO Auto-generated method stub
int max_length = 0;
int temp_length = 0;
for(int i = le; i <=ri; i++){
if(sit[i] == true){
temp_length++;
}else{
if(temp_length > max_length){
max_length = temp_length;
}
temp_length = 0;
}
}
if(temp_length > max_length){
max_length = temp_length;
}
return max_length * 2;
}
}
class LeftParenthese{
private static int static_index = 0;
private int index;
public LeftParenthese(){
index = static_index++;
}
public int getIndex(){
return index;
}
public static void resetStatic(){
static_index = 0;
}
}
虽然我也考虑到了用每个符号的index来进栈,但是我是只统计了已经配对的 "(" 的序号,有几个连续的已配对的 "(" ,该有效括号长度就是 "(" 个数的二倍。还有入栈我新建了一个对象,里面存的index,大可不必如此,就用一个int就可以了,这样反而拖累了速度。
其实呢有更好的方法,可以用配对成功的 ")" 的序号来减去栈中还有的 "("的序号来获得长度的,哎,当时没想到啊。失误失误,摘自别人博客的思路如下:
想要O(n)的解法需要一点技巧,栈中保存的不是‘(’而是‘(’所在的index,在此基础上也要弄清楚几种情况:
每次来了‘(’之后,无条件压栈。如果碰到')'的话,如果栈不为空,就消除栈内剩余的'('
第一:消除掉'('之后,如果栈内还有剩余的‘(’的话,最长的合法长度就是:maxLength = Math.max(i - (int)stack.peek() , maxLength); 也就是取:当前')'的index减去栈顶元素的index 和 原来max_length 两者的最大值。
例如:对于这种情况:()(()(),可以正确的得出最大值为4。
第二:消除掉')'之后,栈内没有剩余的‘(’了。此时需要引入一个新的变量start,用于表示合法括号字符串的起点。
例如:对于这种情况:())()(),可以正确的得出最大值为4。
start初始为-1,之后每次碰到‘)’且栈为空的时候更新为当前‘)’的index。也就是说无法消除的)之后的括号不可能再和前面的括号合并在一起计算最长序列,所以更新start。