目录


题目

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

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

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

leetcode 376. 摆动序列 思考分析_数组

思路分析

画出序列波动图:
leetcode 376. 摆动序列 思考分析_数组_02
可以发现,我们删除的是单调递增或者递减的坡上的结点(不包括坡顶和坡底)
局部最优:删除单调坡度上的结点,那么这个坡度就可以有两个局部峰值
全局最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
实际操作中只需要统计数组中的峰值数量即可。
在实际操作中的时候我们需要用到cur_delta = nums[i] - nums[i-1],pre_delta = nums[i-1] - nums[i-2].
从数组的左端开始,默认序列右端是个峰值。
如果cur_delta >0 && pre_delta <=0 或者 cur_delta <0 && pre_delta >=0,我们认为存在一个峰值。
(因为 pre_delta 被初始化为 0 了,所以这里要加上=号)
并且,只有在存在峰值的时候,我们才更新pre_delta ,因为统计的是峰值,一定是以上一下的,prediff之前是上,接下来就是下

代码

class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if(n<=1) return n;
int peak_nums=1;
int delta_pre_curr=0;
int delta_ppre_pre=0;
for(int i = 1;i < n;i++)
{
delta_pre_curr=nums[i]-nums[i-1];
if((delta_pre_curr > 0 && delta_ppre_pre <= 0) || (delta_pre_curr < 0 && delta_ppre_pre >= 0))
{
peak_nums++;
delta_ppre_pre=delta_pre_curr;
}
}
return peak_nums;
}
};

总结

1.保持区间波动,只需要把单调区间上的元素移除就可以了。
2.因为题目并不需要我们确定最终的序列是什么,所以其实只是要找整个序列单调增/减了几次。
3.为什么可以将previous diff设置为0是因为他只会在一开始等于0,后面他会被current diff更新,并且如果current diff不满足严格正/负变符号他就不会更新previous diff,所以len(nums)==2不需要单独拿出来写几行代码
4. res从1开始记录,因为出发点肯定算一个