leetcode:32. 最长有效括号

题目来源

题目描述

在这里插入图片描述

class Solution {
public:
    int longestValidParentheses(string s) {

    }
};

题目解析

分析数据量

  • 0 <= s.length <= 3 * 10^4:O(N * logN)级别的算法
  • s[i] 为 '(' 或 ')':不需要检查参数有效性

分析题意

要求返回最长有效的子串的长度

动态规划

像这样的题目都是有套路的。只需要这样思考:

  • 必须以0位置结尾而且有效时,往左最长能延伸多长
  • 必须以1位置结尾而且有效时,往左最长能延伸多长

即:

  • 必须以每个位置结尾的情况下,往左延伸多长有效最长的有效长度
  • 每个位置结尾答案如果都能够求出来,整体答案的最大值就是我们想要的
  • 因为从客观上来讲,最长有效子串它必须以某个位置结尾,所以所有结尾的最长长度就是我们想要的

问题是,怎么求每个位置的答案

当来到i位置时

  • 如果str[i] == (,不可能以(结尾,所以dp[i] = 0
  • 如果str[i] == ),它要被哪些因素影响呢?
    • 如果str[i - 1] == (
      • 那么dp[i]至少为2
      • 除此之外,我们还需要看str[i - 2]的位置是什么?
        • str[i - 2] = (,也就是是((),那么dp[i] = 2
          • 此时dp[i - 2] = 0,即dp[i] = 2 + [i - 2]
        • str[i - 2] = ),此时就要看dp[i - 2]最远能推多远
          • 如果dp[i - 2] = 2,那么dp[i] = 2 + dp[i - 2] = 4
          • 如果dp[i - 2] = 4,那么dp[i] = 2 + dp[i - 2] = 6
      • 综上所述: str[i - 1] == ( && str[i] == )时,以 i i i位置结尾要看 i − 2 i - 2 i2位置能推多远, d p [ i ] = 2 + d p [ i − 2 ] dp[i] = 2 + dp[i - 2] dp[i]=2+dp[i2]
      • 也就是,先看 i i i位置能推多远,然后看i-2位置能推多远
    • 如果str[i - 1] == )
      • 这个问题和str[i]的问题是类似的
      • 如果dp[i - 1] = 0,那么dp[i] = 0
      • 那么dp[i - 1] = 2,那么就要看str[i - 3]是否是(
        • 如果不是的话,那么dp[i] = 0
        • 如果是的话,那么 d p [ i ] 至少为 d p [ i − 1 ] + 2 dp[i] 至少为 dp[i - 1] + 2 dp[i]至少为dp[i1]+2,然后还要看pre - 1最远能扩充到哪

综上:

  • str[i] == (时, d p [ i ] = 0 dp[i] = 0 dp[i]=0
  • str[i] == )时:
    • 如果str[i - 1] == ( d p [ i ] = 2 + d p [ i − 2 ] dp[i] = 2 + dp[i - 2] dp[i]=2+dp[i2]
    • 如果str[i - 1] == )
      • 如果 d p [ i − 1 ] = = 0 dp[i - 1] == 0 dp[i1]==0,那么 d p [ i ] = 0 dp[i] = 0 dp[i]=0
      • 如果 d p [ i − 1 ] = = k dp[i - 1] == k dp[i1]==k
        • 如果str[i - k - 1] == ),那么 d p [ i ] = 0 dp[i] = 0 dp[i]=0
        • 如果str[i - k - 1] == (,那么 d p [ i ] = d p [ i − 1 ] + 2 + d p [ ( i − k − 1 ) − 1 ] dp[i] = dp[i - 1] + 2 + dp[(i - k - 1) - 1] dp[i]=dp[i1]+2+dp[(ik1)1]
class Solution {
public:
    int longestValidParentheses(string s) {
        if(s.size() < 2){
            return 0;
        }

        // dp[i] : 子串必须以i位置结尾的情况下,往左最远能扩出多长的有效区域
        int N = s.size();
        std::vector<int> dp(N, 0);
        int pre = 0;
        int ans = 0;
        for (int i = 1; i < N; ++i) {
            if(s[i] == ')'){
                pre = i - dp[i - 1] - 1; // 与str[i]配对的左括号的位置 pre
                if (pre >= 0 && s[pre] == '(') {
                    dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
                }
            }
            ans = std::max(ans, dp[i]);
        }
        return ans;
    }
};

  • 定义start来记录合法括号串的起始位置
  • 遍历字符串
    • 如果遇到(,那么将当前下标入栈
    • 如果遇到)
      • 如果栈为空,则将下一个坐标位置记录到start
      • 如果栈不为空,则将栈顶元素取出,此时如果栈为空,则更新结果和i-start+1中的较大值;此时若栈为空,则更新结果和 i - start + 1 中的较大值,否则更新结果和 i - st.top() 中的较大值
class Solution {
public:
    int longestValidParentheses(string s) {
        int res = 0, start = 0, n = s.size();
        stack<int> st;
        for (int i = 0; i < n; ++i) {
            if (s[i] == '(') st.push(i);
            else if (s[i] == ')') {
                if (st.empty()) start = i + 1;
                else {
                    st.pop();
                    res = st.empty() ? max(res, i - start + 1) : max(res, i - st.top());
                }
            }
        }
        return res;
    }
};

类似题目

题目描述
leetcode:32. 最长有效括号栈、动态规划
leetcode:22. 给定n,生成所有合法的括号组合 generate-parentheses
leetcode:301. 删除无效的括号,得到所有有效的不重复组合 Remove Invalid Parentheses
leetcode:20. 有效的括号 Valid Parentheses
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值