题目链接

本题的难点:刚开始想的话是想用栈匹配的方式来贪心的求解,后面发现"((())(()"这种形式的串贪心的话会将后面部分的算入答案中得到错误结果。那么问题就变成了一个递推式的问题,我们可以使用函数递归的思想来想,假设一个位置i处的左端左括号的数量已经大于右端,然而此时右端的答案并不能直接算进答案之中,因为不知道左端的括号是否能够全部被后面右端的右括号给匹配上,因此只有当左端最后一个括号被匹配上的时候,才能递归的处理左端之前已经匹配上的括号,时间复杂度大概是\(O(N^2)\),这是无法接受的=.=
此时应该用动态规划求解,\(dp[i]\)表示当前位置左端的最大合法匹配长度,易得"("处的值应该全部都是0,对于右括号,我们分为两种情况:

  • \(s[i-1]\)为左括号的时候,我们可以知道此时刚好得到了一对新的匹配,所以此时的\(dp[i]=dp[i-2]+2\)
  • \(s[i-1]\)为右括号的时候,如果\(s[i-1]\)处的右括号也有自己的匹配,我们此时就可以回溯到\(s[i-1]\)最大匹配长度的左端,也就是\(i-dp[i-1]-1\)处,如果此处符号为左括号,那么刚好和当前\(s[i]\)位置的右括号匹配上,我们可以新得到一段从\(i-dp[i-1]-1\)\(i\)处的合法匹配。注意此时没有结束,假设\(i-dp[i-1]-1\)左端还有合法匹配呢?,所以此时得到新的递推方程\(dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2]\)

代码如下

class Solution {
public:
    int longestValidParentheses(string s) {
        int n=s.size();
        vector<int> dp(n+1,0);

        int ans=0;
        for(int i=1;i<n;i++){
            if(s[i]==')'){
                if(i>1&&s[i-1]=='(') dp[i]=dp[i-2]+2;
                else if(i-dp[i-1]>0&&s[i-dp[i-1]-1]=='('){
                    dp[i]=dp[i-1]+2+((i-dp[i-1])>=2?dp[i-dp[i-1]-2]:0);
                }
            }
            ans=max(ans,dp[i]);
        }
        return ans;
    }
};