LeetCode第 32 题:最长有效括号(C++)

32. 最长有效括号 - 力扣(LeetCode)
LeetCode第 32 题:最长有效括号(C++)_第1张图片
如果感觉不好理解的话,就用消消乐的思路去思考就知道怎么做了。

栈处理

栈是括号匹配常用的辅助结构了。

维护一个标志位数组,记录不能匹配的括号的下标。一次遍历:

  • 如果是左括号:入栈
  • 如果是右括号:栈空的话说明该右括号无法匹配,标志位置位;栈非空的话直接出栈即可

最后的标志位数组就是一串0/1的数组,只需要遍历记录最长的连续1的个数就可以了。

class Solution {
public:
    int flags[20000];
    int longestValidParentheses(string s) {
        int n = s.size();
        stack stk;//存储的是下标
        for(int i = 0; i < n; ++i){
            if(s[i] == '(') stk.push(i);//左括号push
            else{
                if(stk.empty())   flags[i] = 1;
                else    stk.pop();
            }
        }
        
        while(!stk.empty()){
            flags[stk.top()] = 1;
            stk.pop();
        }
        
        int res = 0, len = 0;
        for(int i = 0; i < n; ++i){
            if(flags[i] == 0)   ++len;
            else{
                res = max(res, len);//长度更新
                len = 0;
            }
        }
        return max(res, len);//可能需要考虑最后的位
    }
};

动态规划

合法子串的结尾必然是右括号 ),所以状态转移如下:
图来自:动态规划思路详解(c++)——32.最长有效括号 - 最长有效括号 - 力扣(LeetCode)

当s[i]是)时,dp[i]表示以下标 i 结尾的最长有效子字符串的长度
1、s[i-1] == ‘(’:
LeetCode第 32 题:最长有效括号(C++)_第2张图片
那么明显dp[i] = dp[i-2] + 2;

2、s[i-1] == ‘)’:
LeetCode第 32 题:最长有效括号(C++)_第3张图片
此时考虑对称性,dp[i-1]为以s[i-1]为结尾的字符串已匹配的长度,如果这一块长度之前那那个字符刚好是 (,那就可以和s[i]匹配。此时还需要注意上图,i-1-dp[i-1]处的字符即为和s[i]匹配的字符,我们累加长度的时候要把匹配字符的前一个位置i-2-dp[i-1]也加上,这样才能取得最大值。

不匹配的情况直接为0就可以,初始化均为0即可。

可以使用哨兵的思路简化下标处理:

class Solution {
public:
    int dp[20000];
    int longestValidParentheses(string s) {
        s = "-" + s;
        int n = s.size(), res = 0;
        for(int i = 2; i < n; ++i){
            if(s[i] == ')'){//合法的子串一定以右括号结尾
                if(s[i-1] == '(')  dp[i] = dp[i-2] + 2; 
                else if(s[i-1-dp[i-1]] == '(')  dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2;
                res = max(res, dp[i]);
            } 
        }
        return res;
    }
};

当然不用也可以,只是下标会看起来比较乱:

class Solution {
public:
    int dp[20000];
    int longestValidParentheses(string s) {
        int n = s.size();
        for(int i = 1; i < n; ++i){
            if(s[i] == ')'){//合法的子串一定以右括号结尾
                if(s[i-1] == '(')  dp[i+1] = dp[i-1] + 2; 
                else if(i-1-dp[i] >= 0 && s[i-1-dp[i]] == '(')  dp[i+1] = dp[i] + dp[i-1-dp[i]] + 2;
            } 
        }
        return *max_element(dp+1, dp+n+1);
    }
};

你可能感兴趣的:(leetcode)