(重点)[LeetCode]Longest Valid Parentheses

来源:互联网 发布:家电 进销存 源码 编辑:程序博客网 时间:2024/06/05 00:10

Question:
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。有两种算法分别是:stack和DP。

算法1:stack

【复杂度】
时间 O(N) 空间 O(N)

【思路】
用Stack的方法本质上和Valid Parentheses是一样的,一个右括号能消去Stack顶上的一个左括号。不同的是,为了能够计算括号对的长度我们还需要记录括号们的下标。这样在弹出一个左括号后,我们可以根据当前坐标减去栈中上一个(也就是Pop过后的Top元素)的坐标来得到该有效括号对的长度。

【附】
这个算法难在对各种情况的判断,以及对stack的巧妙利用。这个算法我是看了很一会才反应过来((⊙﹏⊙)b)。下面将代码贴出,对于各种情况的处理我也进行了注释。

【注意】
第26行:curLen=i-stack.peek().index;不能是curLen=i-stack上一个pop出的index+1;。如果对于)()(),此时 i=4,如果按照后一种方法,算出的curLen=i-3+1,而正确的应该是curLen=i-0

【代码】

public class Solution {    public int longestValidParentheses(String s) {        //require        if(s==null)            return 0;        int size=s.length();        if(size<2)            return 0;        int ans=0;        Stack<Parenthese> stack=new Stack<Parenthese>();        //invariant        for(int i=0;i<size;i++){            char c=s.charAt(i);            //遇到左括号,将其push进栈            if(c=='(')                stack.push(new Parenthese(c,i));            else{            //遇到右括号,分类讨论                //如果当前栈顶是左括号,则消去并计算长度                if(!stack.isEmpty()&&stack.peek().c=='('){                    int curLen=0;                    stack.pop();                    if(stack.isEmpty())                 //  ()(  )                        curLen=i+1;                    else                                //  ((()  )  or  )()(  )                        curLen=i-stack.peek().index;                    ans=Math.max(ans,curLen);                }else                                   //  )    or    )  )                    //如果栈顶是右括号或者是空栈,则将右括号也push进栈,它的坐标将方便之后计算长度                    stack.push(new Parenthese(c,i));            }        }        //ensure        return ans;    }    class Parenthese{        char c;        int index;        public Parenthese(char c,int index){            this.c=c;            this.index=index;        }    }}

算法2:DP

【复杂度】
时间 O(N) 空间 O(N)

【思路】
动态规划法将大问题化为小问题,我们不一定要一下子计算出整个字符串中最长括号对,我们可以先从后向前,一点一点计算。假设d[i]是从下标i开始到字符串结尾最长括号对长度,s[i]是字符串下标为i的括号。如果s[i-1]是左括号,如果i + d[i] + 1是右括号的话,那d[i-1] = d[i] + 1。如果不是则为0。如果s[i-1]是右括号,因为不可能有右括号开头的括号对,所以d[i-1] = 0。

【附】
我只能再次感慨DP的强大和这个算法的精妙。

【注意】
1、第16行if(end<size&&s.charAt(end)==')'){中的end<size必须要有,以防止(()(当i=0,end=3越界)
2、第19行d[i]+=d[end+1];,别错写为d[i]+=d[end];

【代码】

public class Solution {    public int longestValidParentheses(String s) {        //require        if(s==null)            return 0;        int size=s.length();        if(size<2)            return 0;        int ans=0;        int[] d=new int[size];        //invariant        for(int i=size-2;i>=0;i--){            char c=s.charAt(i);            if(c=='('){                int end=i+d[i+1]+1;                if(end<size&&s.charAt(end)==')'){    // (())                    d[i]=d[i+1]+2;                    if(end+1<size)                   // ()() or ((())())                        d[i]+=d[end+1];                }            }            ans=Math.max(ans,d[i]);        }        //ensure        return ans;    }}

参考

Longest Valid Parentheses(这篇帖子无论是技术探索精神还是写作风格都值得参考)

0 0