动态规划是真的难啊坚持

38 篇文章 1 订阅

动态规划的思路,和官方题解的思路是一样的。在这里我说说我的思考过程。
一开始我没有直接想到dp数组里的每个元素,代表“以该元素结尾的最长有效长度”,而是我把它定义成“到该元素为止前面字符串里最长有效长度”。比如说:
(  (  )  (  (  (  (  )  )
index   0  1  2  3  4  5  6  7  8
dp arr  0  0  2  2  2  2  2  2  4
dp数组的推算如上:碰到左括号则保持不变,碰到右括号,需要看情况:
如果i-1位是左括号,则可以配对成功,但不一定会增加最长有效长度:如果dp[i-1]是0,则说明前面没有有效括号,则可以直接+2。但dp[i-1]大于0,则说明前面肯定出现了有小括号,这时还不能+2,还要看出现过的是否跟本次产生的配对是否连续,连续了才能最长有效长度+2。比如判断index=7时,虽然和index=6配对了,但dp[6]上是2,说明index=6之前还有一对,但它的位置我们没有记下来,无从判断是否跟本次产生的连续。
那么是否可以看index=5上的位置来判断连续呢?比如:如果index=5上是右括号,就说明是连续的?反例:())))()判断最后一位时就会出错。所以还要再往前看一下。——仅仅是i-1位置是左括号就判断很麻烦。
官方题解里把dp数组元素定义为“包含”该元素为末尾元素的最长有效长度,就巧妙解决了该问题:
(  (  )  (  (  (  (  )  )
index   0  1  2  3  4  5  6  7  8
dp arr  0  0  2  0  0  0  0  2  4
左括号对应的dp数组元素全部置0不用管,因为有效括号不可能以左括号结尾。
碰到右括号,先看i-1位置,如果是左括号,配对成功,要+2,在左括号前一位即dp[i-2]的基础上+2。因为dp[i-2]代表了以i-2元素为结尾的有效字串最长长度。比如判断index=7,index=6位置是左括号,可以配对,但要看dp[5]位置的数字,目前是0,为什么是0,因为index=5的位置是左括号,不可能包含它结尾的有效字串。
而判断index=8时,index=7位置是右括号,而dp[7]的值恰好指明了包含它的有效字串最长度,所以让i直接减去dp[7]的值,跳转到“以index=7为结尾的最长有效字串的更前面”,去看看有没有和index=8配对的左括号。
如果有,则是三部分相加:本次的配对长度(2)+ 前面临接的有效长度 + 本次配对左括号更前面的临接的有效长度。
很可能因为本次的配对,导致两个有效长度合并起来,行程更大的长度,比如:

class Solution {
public:
    int longestValidParentheses(string s) {
        vector<int> dp(s.size(), 0);
        int max = 0;
        for (int i = 1; i < s.size(); ++i) {
            if (s[i] == ')') {
                if (s[i - 1] == '(') {
                    dp[i] = 2 + (i >= 2 ? dp[i-2] : 0);
                } else if (i - 1 - dp[i-1] >= 0 && s[i - 1 - dp[i-1]] == '('){
                    if (i - 2 - dp[i-1] >= 0) {
                        dp[i] = 2 + dp[i-1] + dp[i - 2 - dp[i-1]];
                    }
                    else {
                         dp[i] = 2 + dp[i-1];
                    }
                }
            }
            if (dp[i] > max) {
                max = dp[i];
            }
        }

        return max;
    }
};

作者:zhangkekf
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/dong-tai-gui-hua-c-by-zhangkekf/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值