LC.32. 最长有效括号

传送门

挺好的一个题,这里主要再分析一下官方的解法。

思路:

1.

令以下标结尾的字符串的最大长度为,显然.

,需要讨论两种情况。

,这样显然有.

,因为我们已知,我们可以找到的开始匹配的前面 一个位置即,显然如果,是不能更新的,因为一定是未被匹配的,不然会包含掉它,所以显然,才能与进行匹配,然后再加上的长度就可以了。

时间复杂度:

class Solution {
public:
    int longestValidParentheses(string s) {
        int n=s.length(),ans=0;
        vector<int>dp(n,0);
        for(int i=1;i<n;i++){
            if(s[i]=='(') dp[i]=0;
            else if(s[i-1]=='('){
                 dp[i]=(i>=2?dp[i-2]:0)+2;
            }
            else if(i-dp[i-1]>0&&s[i-1-dp[i-1]]=='(')
                dp[i]=(i-2-dp[i-1]>=0?dp[i-2-dp[i-1]]:0)+2+dp[i-1];
            ans=max(ans,dp[i]);
        }
        return ans;
    }
};

2.栈。

显然对于这样的后缀表达式问题,用栈是很方便的。这里是参考官方大大的解法,预先放一个元素,保证栈底是未被匹配的最后一个右括号下标,如果是左括号直接入栈,否则弹出栈顶元素,如果栈是空的表示不能更新,否则长度为

时间复杂度:

class Solution {
public:
    int longestValidParentheses(string s) {
        int n=s.length(),ans=0;
        stack<int>sk;sk.push(-1);
        for(int i=0;i<n;i++){
            if(s[i]=='(') sk.push(i);
            else {
                sk.pop();
                if(sk.empty()) sk.push(i);
                else ans=max(ans,i-sk.top());
            }
        }
        return ans;
    }
};

3.统计左右括号数。

这种方法我觉得比第二种好理解点,先顺序遍历一遍,如果是左括号,否则,左右括号数相等就更新长度,若,则可以舍弃掉前面所有的括号,

因为顺序遍历没有考虑到的情况,这样就更新不了。

所以再逆序遍历一遍,.这样就考虑到所有情况了。

时间复杂度:

class Solution {
public:
    int longestValidParentheses(string s) {
        int n=s.length(),ans=0;
        int l=0,r=0;
        for(int i=0;i<n;i++){
            if(s[i]=='(') l++;
            else r++;
            if(l==r) ans=max(ans,l*2);
            else if(r>l) l=r=0;
        }
        l=r=0;
        for(int i=n-1;i>=0;i--){
            s[i]=='('?l++:r++;
            if(l==r) ans=max(ans,l*2);
            else if(l>r) l=r=0;
        }
        return ans;
    }
};