leetcode 32 dp+栈+两次遍历 多种解法

在这里插入图片描述
这个题真的是一道好题,看起来如此简单,实际却如此复杂(应该说包含了很多知识)。

解法一:dp
此题的dp定义是比较大胆的(其实也挺常规的),就是以当前字符结尾的最长有效长度。说他大胆是因为这样定义的话,所有以左括号结尾的dp值都为0.
状态转移:如果当前字符是右括号,并且上一个是左括号,那么比较简单, d p [ i ] = d p [ i − 2 ] dp[i] = dp[i-2] dp[i]=dp[i2]
接下来就是核心:现在只剩一种情况,就是当前字符是右括号,上一个也是右括号。此时咱们看 d p [ i − 1 ] dp[i-1] dp[i1]这个值,代表上一个的最佳长度。那么 s [ i − d p [ i − 1 ] − 1 ] s[i - dp[i-1] -1] s[idp[i1]1]即为上一个最长串之前的字符,如果这个字符是左括号,那就匹配上了。这样右边的两个右括号就全部匹配完成: d p [ i ] = d p [ i − 1 ] + d p [ i − d p [ i − 1 ] − 2 ] + 2 dp[i] = dp[i-1]+dp[i-dp[i-1]-2]+2 dp[i]=dp[i1]+dp[idp[i1]2]+2

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

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

解法二:栈
先说下算法,真的很难想。
首先初始化栈里有个-1
如果遇见左括号,下标入栈。
如果遇见右括号,直接排出一个元素,然后看栈是否为空。
若空,放入当前下标,否则,当前下标减去栈顶元素更新答案。

算法解释:
这算法看起来真的是太简单了,甚至完全不知道它在干什么。
首先,我们要明确栈中元素的定义:上一个终止符位置,即遇到这个位置的字符,那肯定就不行了。对应的其实是右括号比左括号多的情况,如果右括号多了一个,那肯定没戏了。
所以,这套算法的执行逻辑是,栈顶记录上一个终止符,如果行就持续走,保持更新终止符。匹配也是一样的,左符号多时,左符号视为终止符,就这样持续记录(真变态的算法)

class Solution {
public:
    int longestValidParentheses(string s) {
        vector<int> v{-1};

        int ans = 0;
        for(int i=0;i<s.size();i++)
        {
            if(s[i] == '(')v.push_back(i);
            else
            {
                v.pop_back();
                if(v.size() == 0)v.push_back(i);
                else ans = max(ans, i-v.back());
            }
        }
        return ans;
    }
};

解法三:两次遍历
这个也是老朋友了,和其他两次遍历能解决的问题一样,括号问题在两次遍历中一定有一次能保证取到最优值。
算法:记录左右括号的差值,右括号多时重新开始记录,差值为0时更新答案,两次遍历解决。
这个其实是不太好想的,单次遍历的局限性在于,如果左括号多了,那这部门的答案是得不到的。两次遍历能保证这种情况不会出现。因为对每一个最长串,他两边要么是左括号多,要么是右括号多,总有一次能找到它。

对于这类题目,其实都是有局部限制,即满足一定条件时,此时的值要重新计算:如糖果问题:你比左边小就设置为1,最大乘积子数组:遇见0重新开始算。
归根结底,还是两次遍历一定能让任意一个元素获得最优解。在实际问题中,我们要去分析能不能这样(可能还需要证明)。比如最大乘积子数组,是考虑负元素奇偶性后才能证明的。局部限制问题只能说是一个特例。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值