LeetCode 32. Longest Valid Parentheses【动态规划+栈+括号匹配】⭐⭐⭐⭐⭐

24 篇文章 0 订阅
13 篇文章 0 订阅

题目描述

在这里插入图片描述

知识点

栈、字符串匹配

结果

在这里插入图片描述

实现

码前思考

  1. 看见子串匹配问题,我想到的是滑动窗口,但是很遗憾,我没有找到解决办法;
  2. 再然后看见最长,我想的是动态规划,毕竟是最优化问题嘛,但是也没有想清楚;
  3. 最后,我偷偷看了一下提示,才发现栈,原来之前也是做过括号匹配的题目的,用的就是栈,于是我就想怎么用栈来解决这个问题。
  4. 思路是这样的,既然是栈,那么当匹配好了一对’( )'之后,它们肯定就不在栈里面了,那么怎么保存它们的匹配信息呢?很容易想到就是设定一个数组dp,数组的元素dp[i]表示目前i后面最长的匹配子串(注意是目前),然后每次匹配成功之后就更新弹出栈顶之后的新栈顶的那个元素的dp值;
  5. 上面只是大概的思路,其实还有很多细节需要考虑清楚,例如:
    1. 如果字符串全部匹配,栈顶会为空,这怎么办?
    2. 需要将弹栈的元素的dp值加到新的栈顶的dp值,还要再加2;
    3. 等等,都需要通过手写模拟测试用例,认真分析得来的。

代码实现

//依然是采用栈的方式,只不过每次都要记录一个数据
//dp[i]表示i后面最长的匹配子串,不包含i
class Solution {
public:
    int longestValidParentheses(string s) {
        int size = s.size();
        if(size == 0){  //特判
            return 0;
        }
        //设置dp数组,初始化为0
        vector<int> dp(size+1,0);
        
        stack<int> st;

        //首先压入一个-1,表示开始
        st.push(-1);

        //开始进行压栈操作
        for(int i=0;i<size;i++){    //遍历每一个
            //读入当前的字符
            char cur = s[i];
            //如果当前字符是'('
            if(cur == '('){
                //直接进行压栈
                st.push(i);
            }
            //如果当前字符是右括号
            if(cur == ')'){
                //并且栈不为空而且栈顶是'('
                if(st.top() != -1){
                    int topIdx = st.top();
                    char topChar = s[topIdx];
                    if(topChar == '('){
                        //说明匹配,那么需要进行弹出栈顶并且更新
                        st.pop();
                        dp[st.top()+1] = dp[topIdx+1] + 2 + dp[st.top()+1];
                    }else{
                        st.push(i);
                    }
                }else{
                    st.push(i);
                }
            }
        }

        int ans = 0;
        for(int i=0;i<=size;i++){
            ans = max(dp[i],ans);
        }

        return ans;
    }
};

码后反思

  1. 其实不用使用数组记录的,只要用左右数组下标相减就可以了!这个自己动手模拟一下,手写一下就出来:
    在这里插入图片描述
    //依然是采用栈的方式,只不过每次都要记录一个数据
    //dp[i]表示i后面最长的匹配子串,不包含i
    class Solution {
    public:
        int longestValidParentheses(string s) {
            int size = s.size();
            if(size == 0){  //特判
                return 0;
            }
            
            stack<int> st;
    
            //首先压入一个-1,表示开始
            st.push(-1);
            
            int ans = 0;
    
            //开始进行压栈操作
            for(int i=0;i<size;i++){    //遍历每一个
                //读入当前的字符
                char cur = s[i];
                //如果当前字符是'('
                if(cur == '('){
                    //直接进行压栈
                    st.push(i);
                }
                //如果当前字符是右括号
                if(cur == ')'){
                    //并且栈不为空而且栈顶是'('
                    if(st.top() != -1){
                        int topIdx = st.top();
                        char topChar = s[topIdx];
                        if(topChar == '('){
                            //说明匹配,那么需要进行弹出栈顶并且更新
                            st.pop();
                            ans = max(i-st.top(),ans);
                        }else{
                            st.push(i);
                        }
                    }else{
                        st.push(i);
                    }
                }
            }
    
            return ans;
        }
    };
    

需要注意设置-1的巧妙之处!
2. 还可以用动态规划,还有一种更加巧妙地解法,这里就不提了。

参考文档

  1. 一道 LeetCode 的多种解法,打消了我的自以为是!

二刷代码

使用动态规划和栈进行解题即可

//见到最长就要想动态规划,这种最优解问题
class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        int len = s.size();
        if(len == 0 || len == 1){
            return 0;
        }
        //拼接一下
        s='#'+s+'#';
        vector<int> dp(s.size(),0);//初始化为1
        st.push(0);

        for(int i=1;i<s.size()-1;i++){
            if(s[i]=='('){
                st.push(i);
            }else{
                int idx = st.top();
                if(s[idx]=='('){
                    st.pop();
                    int newIdx = st.top();
                    dp[newIdx] += dp[idx] + 2;
                }else{
                    st.push(i);
                }
            }
        }

        int res=INT_MIN;
        //然后进行求最大值
        for(int i=0;i<s.size()-1;i++){
            res=max(res,dp[i]);
        }

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值