LeetCode 376. Wiggle Subsequence(动态规划)

题目

给出一个整数序列,求摆动子序列,即子序列相邻两位之间的差值正负交替出现的,即序列中相邻两个数一大一小交替出现。

Examples:
Input: [1,7,4,9,2,5]
Output: 6
The entire sequence is a wiggle sequence.

Input: [1,17,5,10,13,15,10,5,16,8]
Output: 7
There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].

Input: [1,2,3,4,5,6,7,8,9]
Output: 2

思路

和之前动态规划做的Best Time to Buy and Sell Stock with Transaction Fee思路一模一样,这里再简单说一下好了。

满足题意的序列最后两个数的差值要么是正数,要么是负数,因此可以用两个数组记录两种信息,然后交替更新到数组最后一位即可。

定义状态
    pos[i]: 从nums[0]到nums[i]范围内符合条件的最长子序列长度,而且最后一个差值是正数
    neg[i]: 从nums[0]到nums[i]范围内符合条件的最长子序列长度,而且最后一个差值是负数
    额外需要pos_end,neg_end记录两个序列的最后一位数字
    最终结果为 max(pos[n - 1], neg[n - 1])
状态转移

这里写图片描述
可见每个状态都由之前的两个状态转移过来

更新pos[]
①当nums[i] - pos_end > 0时,nums[i]不能直接加到pos序列最后否则连续两个差值都是正值就违反规定了,但是由贪心策略,此时用nums[i]替换掉pos_end会使得以后寻找下一个数更有利,因为pos_end越大的话,下一个满足序列条件的数的范围也越大(下一个满足条件的数一定小于pos_end),因此 pos_end = nums[i] , pos[i] = pos[i - 1]

②当nums[i] - neg_end > 0时,pos_end = nums[i],pos[i] = neg[i - 1] + 1

则 pos[i] = max(pos[i - 1],neg[i - 1] + 1)

类似的更新neg[]
③当nums[i] - pos_end < 0时,neg_end = nums[i],neg[i] = pos[i - 1] + 1

④当nums[i] - neg_end < 0时,neg_end = nums[i],neg[i] = neg[i - 1]

则 neg[i] = max(neg[i - 1],pos[i - 1] + 1)

注意:当nums[i] - pos_end == 0时,pos序列的长度和最后一个数都不变,类似的当nums[i] - neg_end == 0时也一样,这里的赋值问题有点坑,直接看代码就清楚了

代码

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1) return n;

        //pos[i]: 从nums[0]到nums[i]范围内符合条件的最长子序列长度,而且最后一个差值是正数
        //neg[i]: 从nums[0]到nums[i]范围内符合条件的最长子序列长度,而且最后一个差值是负数
        vector<int> pos(n);
        vector<int> neg(n);
        int pos_end = nums[0], neg_end = nums[0];
        pos[0] = neg[0] = 1;


        for (int i = 1; i < n; i++) {
            // pos数组期待下一个差值是负值,neg期待下一个差值是正值
            int expect_neg_diff = nums[i] - pos_end;
            int expect_pos_diff = nums[i] - neg_end;

            int lenx, leny;

            // 更新pos[i],
            // 给lenx和leny初始化长度为pos[i - 1],
            // 既满足nums[i] - pos_end == 0时的情况,
            // 也能避免当下面两个条件都不满足时出现lenx和leny为乱值。
            lenx = leny = pos[i - 1];
            if (expect_neg_diff > 0) {
                pos_end = nums[i];
                lenx = pos[i - 1];
            }
            if (expect_pos_diff > 0) {
                pos_end = nums[i];
                leny = neg[i - 1] + 1;
            }
            pos[i] = max(lenx, leny);

            // 更新neg[i],初始化lenx和leny的理由同上
            lenx = leny = neg[i - 1];
            if (expect_pos_diff < 0) {
                neg_end = nums[i];
                lenx = neg[i - 1];
            }
            if (expect_neg_diff < 0) {
                neg_end = nums[i];
                leny = pos[i - 1] + 1;
            }
            neg[i] = max(lenx, leny);
        }


        return max(pos[n - 1], neg[n - 1]);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值