代码随想录|贪心算法|03摆动序列

leetcode:376. 摆动序列 - 力扣(LeetCode)

题目

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。

例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3)  是正负交替出现的。相反, [1,4,7,2,5]  和  [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。

示例 1:

  • 输入: [1,7,4,9,2,5]
  • 输出: 6
  • 解释: 整个序列均为摆动序列。

示例 2:

  • 输入: [1,17,5,10,13,15,10,5,16,8]
  • 输出: 7
  • 解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。

示例 3:

  • 输入: [1,2,3,4,5,6,7,8,9]
  • 输出: 2

思路

其实一开始我想的是把差值数组求出来,然后再搞,但是看到了随想录上面的图,如下:

那这样子就好处理了,对于连续上升或者连续下降的,把中间的去掉,只保留两端的,我们不需要在数组上进行删除啊这些的操作,本来题目就是让我们统计数量罢了,没说要求具体的数组。

那就这样:

prediff=nums[i]-nums[i-1]

curdiff=nums[i+1]-nums[i]

在for(int i=1;i<nums.size()-1;i++)里面满足下面条件

if(           (prediff<0&&curdiff>0)      ||       (prediff>0&&curdiff<0)    )

我们才会计数count++,

但是呢我写的这种,漏掉了首尾两个元素,然后我又单独加了首尾元素的判断逻辑,仍然无法全部AC,然后才看随想录的思路。

当然我的大体判断思路是对的,但是本题要考虑三种情况:

  1. 情况一:上下坡中有平坡
  2. 情况二:数组首尾两端
  3. 情况三:单调坡中有平坡

情况一:上下坡中有平坡

这里面的四个2,实际上只有一个2是有用的,统一规则我们就只保留最右边的这个2,如下:

 

当i指向最后一个2,满足prediff = 0 && curdiff < 0,所以说这种情况也要放到判断条件里面,也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。

把这个条件融入到已有条件中,就变成:preDiff >= 0 && curDiff < 0

同理还有:preDiff <= 0 && curDiff > 0

那么现在if里面的条件就是:(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)

情况二:数组首尾两端

题目中说了,如果只有两个不同的元素,那摆动序列也是 2

例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。

因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。

这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为 2。(我自己写是这么做的),但是可以融入到上面的if里面吗?

之前我们在 讨论 情况一:相同数字连续 的时候, prediff = 0 ,curdiff < 0 或者 >0 也记为波谷。

那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即 preDiff = 0,如图:

这种情况下result初始化为1,意思是默认最右边有一个峰值,此时 preDiff <= 0&&curDiff > 0,所以result++变成最终结果2。

此时代码如下:

// 版本一
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        int curDiff = 0; // 当前一对差值
        int preDiff = 0; // 前一对差值
        int result = 1;  // 记录峰值个数,序列默认序列最右边有一个峰值
        for (int i = 0; i < nums.size() - 1; i++) {
            curDiff = nums[i + 1] - nums[i];
            // 出现峰值
            if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
                result++;
            }
            preDiff = curDiff;
        }
        return result;
    }
};

还是无法AC!!!所以还有个情况三!

情况三:单调坡度有平坡

如果在一个单调坡度上有平坡,例如[1,2,2,2,3,4],如图:

这种问题的出现是因为prediff一直在更新,我们需要更改为:

只有坡度变化的时候,才可以更新prediff

最后代码如下:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        int curDiff = 0; // 当前一对差值
        int preDiff = 0; // 前一对差值
        int result = 1;  // 记录峰值个数,序列默认序列最右边有一个峰值
        for (int i = 0; i < nums.size() - 1; i++) {
            curDiff = nums[i + 1] - nums[i];
            // 出现峰值
            if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
                result++;
                preDiff = curDiff; // 注意这里,只在摆动变化的时候更新prediff
            }
        }
        return result;
    }
};

总结

这道题需要考虑的就是平坡出现的情况,有下面两种:

包括将最右边区间默认设定一个峰值,这种操作都很男想到。 

参考资料

 代码随想录

贪心算法,寻找摆动有细节!| LeetCode:376.摆动序列_哔哩哔哩_bilibili 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值