LC.32. 最长有效括号

    技术2025-01-14  43

    LC.32. 最长有效括号

    传送门

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

    思路:

    1. d p dp dp

    令以下标 i i i结尾的字符串的最大长度为 d p [ i ] dp[i] dp[i],显然 s [ i ] = ′ ( ′ s[i]='(' s[i]=( d p [ i ] = 0 dp[i]=0 dp[i]=0.

    s [ i ] = ′ ) ′ s[i]=')' s[i]=),需要讨论两种情况。

    1 : 1: 1: s [ i − 1 ] = ′ ( ′ s[i-1]='(' s[i1]=( ,这样显然有 d p [ i ] = d p [ i − 2 ] + 2 dp[i]=dp[i-2]+2 dp[i]=dp[i2]+2.

    2 : s [ i − 1 ] = ′ ) ′ 2:s[i-1]=')' 2:s[i1]=) ,因为我们已知 d p [ i − 1 ] dp[i-1] dp[i1],我们可以找到 d p [ i − 1 ] dp[i-1] dp[i1]的开始匹配的前面 一个位置即 p o s = ( i − 1 ) − d p [ i − 1 ] pos=(i-1)-dp[i-1] pos=(i1)dp[i1],显然如果 s [ p o s ] = ′ ) ′ s[pos]=')' s[pos]=),是不能更新的,因为 s [ p o s ] s[pos] s[pos]一定是未被匹配的 ′ ) ′ ')' ),不然 d p [ i − 1 ] dp[i-1] dp[i1]会包含掉它,所以显然 s [ p o s ] = ′ ( ′ s[pos]='(' s[pos]=(,才能与 s [ i ] = ′ ) ′ s[i]=')' s[i]=)进行匹配,然后再加上 d p [ p o s − 1 ] dp[pos-1] dp[pos1]的长度就可以了。

    d p [ i ] = d p [ i − 1 ] + 2 + d p [ i − 2 − d p [ i − 1 ] ] dp[i]=dp[i-1]+2+dp[i-2-dp[i-1]] dp[i]=dp[i1]+2+dp[i2dp[i1]]

    时间复杂度: O ( n ) O(n) O(n)

    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.栈。

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

    时间复杂度: O ( n ) O(n) O(n)

    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.统计左右括号数。

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

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

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

    时间复杂度: O ( 2 n ) O(2n) O(2n)

    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; } };
    Processed: 0.010, SQL: 9