Longest Valid Parentheses

题目描述:

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.

我之前一直陷入了一个误区,一直用动态规划方法去找右括号,这是很难找的,例如"( ) ( ( ) )"这个例子,dp[4]=2,dp[5]=6.

然后换一个思路:

一维简单动态规划,思想是:对S中从后向前的每个 ' ( ' ,我们来计算它最远对应到的那个‘)’的位置,在这两个字符中间的字符能够组成一个合法的括号串。

记当前 '(' 的下标为 i ,用idx[] 来保存每个i的最右合法匹配位置:

1. 如果它的右边是 ' ) ',那明显最远的合法匹配位置就到这个‘)’为止,idx[i] = i+1;

2.如果它的右边是 ' ( ',因为我们已经计算过它的最右合法匹配位置,在接着这个最右位置继续向右找 ;

3.如果右边不是 ‘( )’,则没有合法的匹配位置, idx = -1 ;

 

例子: 比如  s = " ( ) ( ( ( ) ) "

序号     0    1     2   3   4   5   6   7

             (      )     (    (    (    (     )    )

 

现在来计算idx的值;

1.从右向左找到第一个 ‘ ( ’,序号为5,右边是 ‘)’,匹配,所以 idx[ 5 ] = 6;

2.第二个s[4] ,右边是'(' ,它的匹配是6,所以跳到6再看右边,是‘)’,匹配,所以 idx[ 4 ] = 7;

3. 第三个s[3],右边是 '( " ,它的匹配是7,跳到7再看右边,越界,没有匹配,所以idx[3] = -1;

4.第四个s[2] ,右边是‘(’,但右边的‘(‘的idx为-1,即没有合法的匹配,所以s[2]自然也不能向右有合法匹配,idx[2]=-1;

5. s[0]  = 1;

 

所以得到 idx 数组  :

序号     0    1     2   3   4   5   6   7

             (      )     (    (    (    (     )    )

idx        1    -1    -1 -1  7   6  -1   -1

得到 idx 数组之后,再来计算最大长度,碰到不是-1的就一直往它对应的右括号走,一直累加,碰到-1就计算前面的值,当然最后在最外层还要计算一次,代码如下:

public class Solution {
    public int longestValidParentheses(String s){
    	int n=s.length();
    	int longest=0;
    	int[] idx=new int[n];
    	looper:for(int i=n-1;i>=0;i--){
    		if(s.charAt(i)==')')
    			idx[i]=-1;
    		if(s.charAt(i)=='('){
    			if(i==n-1){
    				idx[i]=-1;
    			}else{
    				if(s.charAt(i+1)==')')
    					idx[i]=i+1;
    				else{
    					int j=i+1;
    					while(s.charAt(j)=='('){
    						int index=idx[j];
    						if(index==-1){
    							idx[i]=-1;
    							continue looper;
    						}
    						j=index+1;
    						if(j==n){
    							idx[i]=-1;
    							continue looper;
    						}
    					}
    					idx[i]=j;
    				}
    			}
    		}
    	}
    	int cur=0;
    	for(int i=0;i<s.length();){  
            if (idx[i]==-1)  
            {  
                longest=Integer.max(longest,cur);  
                cur=0;  
                i++;  
            }  
            else  
            {  
                cur+=idx[i]-i+1;  
                i=idx[i]+1;  
            }  
        }
    	longest=Integer.max(longest,cur);  
    	return longest;
    }
}

还有2个简单的方法:

一种来回两次遍历字符串,让多余的全部都变成"#"。

如"()()))((()(())(()))((())(()()()()()()(((((())))))())()())()(())(())())))))(())()((((((((()()(())))))())())))()(((()())()))(((()()((((("

变成:"()()##((()(())(()))((())(()()()()()()(((((())))))())()())()(())(())())####(())()((((((((()()(())))))())())))()(((()())()))###()()#####"

代码如下:

public class Solution {
    public int longestValidParentheses(String s) {
        char[] c = s.toCharArray();
        int len = c.length, t = 0, ans = 0;
        for (int i = 0, y = 0; i < len; i++){
            if (c[i] == '(')
                y++;
            else if (c[i] == ')' && --y < 0) {
                y = 0;
                c[i] = '#';
            }
        }
        for (int i = len - 1, y = 0; i >= 0; i--) {
            if (c[i] == ')')
                y++;
            else if (c[i] == '(' && --y < 0) {
                y = 0;
                c[i] = '#';
            }

            t = (c[i] == '#') ? 0 : t + 1;
            ans = Math.max(ans, t);
        }
        System.out.println(new String(c));

        return ans;
    }
}

另一种用栈:


public class Solution {
    public int longestValidParentheses(String s) {
	    int max=0,start=0;
	    Stack<Integer> stack=new Stack<Integer>();
	    int[] a=new int[s.length()];
	    char[] c=s.toCharArray();
	    for(int i=0;i<c.length;i++){
	        if(c[i]=='(') stack.push(i);
	        else if(!stack.empty()){
	            start=stack.pop();
	            a[i]=i-start+1;
	            if(start>1) a[i]+=a[start-1];
	            max=Math.max(max,a[i]);
	        }
	    }
	    return max;
	}
}


你可能感兴趣的:(java,LeetCode,动态规划)