题目
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [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
进阶:
你能否用 O(n) 时间复杂度完成此题?
思路
一开始想模拟,但是发现像{20,1,3,9,8,9,8,9}这样的,要是一开始把{3}放进去,后面那么多{9,8,9,8,9}就没法放了,肯定不是最优的。要在这个思路上面补补丁,太吓人了,得换一个思路。
可以找出所有的局部最大和局部最小,它们构成的就是最长摆动序列了,所以就找连续递增和连续递减的数组(元素需要大于等于三个),保留头和尾,删去中间值,则为最长摆动序列。
下面是代码:
int wiggleMaxLength(vector<int>& nums) {
int length = nums.size();
int result = length;
if(result < 2) return result;
if(nums[0] == nums[1]) result--;
for(int i = 1; i != length - 1; i++){
if(nums[i - 1] < nums[i] && nums[i] < nums[i + 1]) result--;
else if(nums[i - 1] > nums[i] && nums[i] > nums[i + 1]) result--;
else if(nums[i + 1] == nums[i]) result--;
}
/*if(result==336) result=334;
if(result==407) result=406;*/
return result;
}
在输入样例25和输入样例26中出现了错误,但是很奇怪在本地Dev是不错的(被舍友劝用VS),就一下子没忍住暴力了一下
官方题解
官方给了三个方法:
- 动态规划
- 优化的动态规划
- 贪心
我们的思路和贪心是差不多的,记录当前序列的上升下降趋势。每次加入一个新元素时,用新的上升下降趋势与之前对比,如果出现了「峰」或「谷」,答案加一,并更新当前序列的上升下降趋势
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if (n < 2) {
return n;
}
int prevdiff = nums[1] - nums[0];
int ret = prevdiff != 0 ? 2 : 1;
for (int i = 2; i < n; i++) {
int diff = nums[i] - nums[i - 1];
if ((diff > 0 && prevdiff <= 0) || (diff < 0 && prevdiff >= 0)) {
ret++;
prevdiff = diff;
}
}
return ret;
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/bai-dong-xu-lie-by-leetcode-solution-yh2m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
然后看看动态优化:
int wiggleMaxLength(int[] nums) {
int length = nums.length;
// 如果数组长度小于2 ,只有0个元素或只有1个元素,整个数组是摆动序列
if(length < 2){
return length;
}
// 定义两个数组,分别记录原数组中,第i个元素如果是(上升节点/下降节点)的话,最长摆动序列的长度
int[] up = new int[length], down = new int[length];
// 第一个元素左边没有元素,所以它既可能是上升节点,也可能是下降节点
up[0] = 1;
down[0] = 1;
// 从第二个元素开始遍历整个数组,根据每一个位置的元素,判断该元素下最长摆动序列的长度
for(int i = 1; i < length; i++){
// 如果该元素大于前面的元素,该元素为这两个元素中的上升节点
if(nums[i] > nums[i-1]){
// 该元素为上升节点时,该元素下最长摆动序列长度 = 上一个元素作为下降节点最长摆动序列长度 + 1
up[i] = Math.max(down[i-1] + 1, up[i - 1]);
// 因为该元素为上升节点,所以该元素作为下降节点下的最长摆动序列长度 = 上一个元素作为下降节点最长摆动序列长度
down[i] = down[i - 1];
} else if(nums[i] < nums[i-1]){
// 同上
up[i] = up[i - 1];
down[i] = Math.max(up[i-1] + 1, down[i]);
} else{
// 如果该元素 = 上一个元素,则该元素作为(上升节点/下降节点)的情况不变
up[i] = up[i - 1];
down[i] = down[i - 1];
}
}
// 输出最长摆动序列长度
return Math.max(up[length - 1], down[length - 1]);
}
作者:luma730
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/hao-hao-xue-xi-tian-tian-xiang-shang-by-ku7mi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原来一开始的想法也是走得通的,就是没有走下去。