https://leetcode.cn/problems/wiggle-subsequence/
题目要求
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
- 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
- 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
贪心## 标题
class Solution {
public int wiggleMaxLength(int[] nums) {
int n = nums.length;
if (n < 1) return n;
int res = 1;
int curGap;// 当前差值
int preGap = 0;// 上一个差值
for (int i = 1; i < n; i++) {
curGap = nums[i] - nums[i - 1];
if ((preGap <= 0 && curGap > 0) || (preGap >= 0 && curGap < 0)) {
res++;
preGap = curGap;
}
}
return res;
}
}
- 删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)。这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点
- 情况一:上下坡中有平坡
- 当i指向第一个2的时候,
preGap > 0 &&
curGap = 0
,当 i 指向最后一个2的时候preGap = 0 && curGap < 0
。 - 如果我们采用,删左面三个2的规则,那么 当
preGap = 0 && curGap < 0
也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。 - 所以我们记录峰值的条件应该是:
(preGap <= 0 && curGap > 0) || (preGap >= 0 && curGap < 0)
,为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。
- 当i指向第一个2的时候,
- 情况二:数组首尾两端
- 只有两个不同的元素,那摆动序列也是2。
- 例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。
- 这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为2。不写死的话,如果和我们的判断规则结合在一起呢?可以假设,数组最前面还有一个数字,那这个数字应该是什么呢?
- 之前我们在 讨论 情况一:相同数字连续 的时候, prediff = 0 ,curdiff < 0 或者 >0 也记为波谷。那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0。
- 情况三:单调坡中有平坡
- 我们只需要在 这个坡度 摆动变化的时候,更新prediff就行,这样prediff在 单调区间有平坡的时候 就不会发生变化,造成我们的误判。
- 情况一:上下坡中有平坡