[LeetCode 32] 最长有效括号

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。


没睡醒的脑回路:转换成 +1,-1 序列,利用两个充要条件(子段和为 0,子段任意前缀的和非负),在前缀和序列上用二分找满足条件的最远点

class Solution {
public:
    int longestValidParentheses(string s) {
        // 对前缀和序列 a,假设 s[i]='('
        // 令 j 为 i 右侧 a[i]-2 首次出现位置(不存在则为 n)
        // 则任意 i<k<j 满足 a[k]=a[i]-1 的 k 都是合法的右端点,贡献 k-i+1
        int n=s.length();
        if(n==0) return 0;

        vector<int> a(n);
        a[0]=s[0]=='('?1:-1;
        for(int i=1;i<n;i++) if(s[i]=='(') a[i]=a[i-1]+1; else a[i]=a[i-1]-1;
        
        vector<vector<int>> o(n+n+2,vector<int>(1,-1));
        for(int i=0;i<n;i++) o[a[i]+n+1].push_back(i);
        for(int i=0;i<n+n+2;i++) o[i].push_back(n);

        int ans=0;

        for(int i=0;i<n;i++) 
        {
            if(s[i]!='(') continue;
            int start=i,stop;
            if(a[i]-2+n+1<0) stop=n;
            else stop=*lower_bound(o[a[i]-2+n+1].begin(),o[a[i]-2+n+1].end(),start);
            auto ptr=lower_bound(o[a[i]-1+n+1].begin(),o[a[i]-1+n+1].end(),stop);
            if(ptr==o[a[i]-1+n+1].begin()) continue;
            --ptr;
            if(ptr==o[a[i]-1+n+1].end()) continue;
            int end=*ptr;
            if(end==n) continue;
            ans=max(ans,end-start+1);
        }

        return ans;
    }
};

注意到删除任意前缀后,无法匹配的括号仍然无法匹配。用栈模拟并标记所有可以匹配的括号后,求最长连续全 1 段即可

上一篇:位段(详解)


下一篇:【组队学习】【32期】吃瓜教程——西瓜书+南瓜书