【算法31天:Day31】第八章贪心算法 LeetCode 摆动序列(376)

60 阅读1分钟

题目二:

image.png

解法一:(贪心算法)

用示例二来举例,如图所示:

376.摆动序列

局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值

整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列

局部最优推出全局最优,并举不出反例,那么试试贪心!

(为方便表述,以下说的峰值都是指局部峰值)

实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)

这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点

本题代码实现中,还有一些技巧,例如统计峰值的时候,数组最左面和最右面是最不好统计的。

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

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

376.摆动序列1

针对以上情形,result初始为1(默认最右面有一个峰值),此时curDiff > 0 && preDiff <= 0,那么result++(计算了左面的峰值),最后得到的result就是2(峰值个数为2即摆动序列长度为2)

var wiggleMaxLength = function(nums) {
    if (nums.length <= 1) return nums.length
    let curDiff = 0 // 当前一对差值
    let preDiff = 0 // 前一对差值
    let result = 1 // 记录峰值个数,序列默认序列最右边有一个峰值
    for (let i = 0; i < nums.length - 1; i++) {
        curDiff = nums[i + 1] - nums[i]
        // 出现峰值
        if ((curDiff > 0 && preDiff <= 0) || (preDiff >=0 && curDiff < 0)) {
            result++
            preDiff = curDiff
        }
    }
    return result
};