摆动序列

力扣题目链接(opens new window)

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

例如, [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

思路

由题目可知,我们需要做的是找出输入数组中出现"波动"的子序列

这个子序列可以不是连续的(如示例2)

根据题目描述,我们可以将"波动"用图画出来(以示例2为例),大概会呈一个折线的样式

如图所示,我们寻找的是一个整数序列中满足"波动"条件的元素组成的一个序列

在结果中其他元素是可以被忽略的

开始找局部和全局最优

局部最优解:删除出现波动的两个元素构成的坡度上的多余的点,那么该坡度会出现两个波动值,即局部峰值,一个波峰一个波谷

全局最优解:整个输入数组有尽可能多的局部峰值

这里的贪心在贪什么?

贪的是让应该构成峰值的地方尽可能的构成峰值

比如5和15,原本可以构成峰值,但是中间隔了很多元素,那我现在把隔着的玩意删了(不一定要真的删,忽略也行),那不就促成5和15的峰值了吗

摆动条件

现在定义两个变量:前差值prediff当前差值curdiff

对应到图中如上,17这个位置出现了prediff > 0 && curdiff < 0因此构成一个波动

移动到下一个波动位置,prediff = curdiff,然后重新计算curdiff

此时curdiff = 10,满足条件prediff < 0 && curdiff > 0,又构成一个波动

显然实际情况会更复杂,这里还需要将情况进行细分:

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

例如 [1,2,2,2,1]

这里的摆动序列其实是[1,2,1],也就是输出结果一个为3

我们要么删掉左边三个2,要么删掉右边三个2,现在统一删左边的

在图中,当i指向第一个2的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个2的时候 prediff = 0 && curdiff < 0

因为删除的是左边的,因此当满足条件prediff = 0 && curdiff < 0时也要记录一次峰值波动

结合前面对于摆动条件的分析,可以得到包含情况一的摆动条件,即:

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

情况二:数组首尾两端

通过上面的分析可以发现,不论是哪种判断,都需要使用至少3个数来进行

如果出现以下情况就有问题了:

	2
/
1

这样的情况无法计算prediff和curdiff

但是题目说了:“少于两个元素的序列也是摆动序列”

也就是说,[1,2]实际上算一个摆动序列,且长度为2

为了统一判断逻辑,这里可以给上述情况设置一个初始值(相当于将[1,2]改成[1,1,2])

	 2
/
1--1

这样就满足了prediff = 0 && curdiff > 0的条件

在代码实现时,仅需将结果记录变量res的初始值设置为1即可

代码

在代码实现时,按常理来说,每次记录完res之后要更新prediff为curdiff,这样相当于每次都更新prediff,curdiff没变化也更新

class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
//定义前差值prediff和当前差值curdiff
int prediff = 0;
int curdiff = 0;
int res = 1;//初始化结果变量,防止只有两个数的情况
for(int i = 0; i < nums.size() - 1; ++i){//遍历数组,计算curdiff
curdiff = nums[i + 1] - nums[i];
if((prediff >= 0 && curdiff < 0)||(prediff <= 0 && curdiff >0)){
res++;
}
prediff = curdiff;//每次都更新
}
return res;
}
};

这回导致问题,因为数组还会出现以下情况

                   3
/
2-2-2-2
/
1

如果每次都更新prediff,就会出现prediff == curdiff的情况

这会使代码把平坡处也记录为摆动

但实际上这个数组的摆动序列是[1,3],在这里平坡不能算波动

平坡算一个上坡的过程中的中间节点,所以实际上应该转变成以下形式

           3
/
1-1

1是初始化res得到的

所以,正确的代码应该指在满足波动条件时更新prediff

class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
//定义前差值prediff和当前差值curdiff
int prediff = 0;
int curdiff = 0;
int res = 1;//初始化结果变量,防止只有两个数的情况
for(int i = 0; i < nums.size() - 1; ++i){//遍历数组,计算curdiff
curdiff = nums[i + 1] - nums[i];
if((prediff >= 0 && curdiff < 0)||(prediff <= 0 && curdiff >0)){//判断波动条件
res++;//记录波动次数,即摆动序列的长度
prediff = curdiff;//每次都更新
}
}
return res;
}
};

【LeetCode贪心#02】摆动序列,麻了的更多相关文章

  1. LeetCode算法训练-贪心算法 455.分发饼干 376. 摆动序列 53. 最大子序和

    欢迎关注个人公众号:爱喝可可牛奶 LeetCode算法训练-贪心算法 455.分发饼干 376. 摆动序列 53. 最大子序和 前置知识 贪心算法核心是找局部最优解,通过局部最优推导出全局最优 Lee ...

  2. 【LeetCode】NO.376 摆动序列 (Python) [贪心算法]

    376. 摆动序列 题目 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 .第一个差(如果存在的话)可能是正数或负数.仅有一个元素或者含两个不等元素的序列也视作摆动序列. 例 ...

  3. LeetCode——376.摆动序列

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

  4. Leetcode 376.摆动序列

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

  5. Java实现 LeetCode 376 摆动序列

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

  6. [Swift]LeetCode376. 摆动序列 | Wiggle Subsequence

    A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...

  7. ALGO-9_蓝桥杯_算法训练_摆动序列(DP)

    问题描述 如果一个序列满足下面的性质,我们就将它称为摆动序列: . 序列中的所有数都是不大于k的正整数: . 序列中至少有两个数. . 序列中的数两两不相等: . 如果第i – 1个数比第i – 2个 ...

  8. Java 第十一届 蓝桥杯 省模拟赛 正整数的摆动序列

    正整数的摆动序列 问题描述 如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列.即 a[2i]<a[2i-1], a[2i+1]>a[2i]. 小明想知道,长度为 m ...

  9. Java实现 蓝桥杯VIP 算法训练 摆动序列

    问题描述 如果一个序列满足下面的性质,我们就将它称为摆动序列: 1. 序列中的所有数都是不大于k的正整数: 2. 序列中至少有两个数. 3. 序列中的数两两不相等: 4. 如果第i – 1个数比第i ...

  10. SYCOJ2100摆动序列

    题目-摆动序列 (shiyancang.cn) 直接分成两部分,插入即可.只有一个地方不对,那就是符号.两个大的放一个小的,两个小的放一个大的.那么每次的大的放最大的,每次的小的放其次小的,用完就不用 ...

随机推荐

  1. ChatGPT背后的AI背景、技术门道和商业应用(万字长文,建议收藏)

    作者:京东科技 李俊兵 各位看官好,我是球神(江湖代号). 自去年11月30日ChatGPT问世以来,迅速爆火出圈. 起初我依然以为这是和当年Transformer, Bert一样的"热点& ...

  2. React中函数组件与类组件的两种使用

    React 创建组件的两种方式 函数组件:使用js函数创建的组件 约定1:函数名称必须以大写字母开头 约定2:函数组件必须要有返回值. 如果返回值为null.表示不渲染任何内容. return nul ...

  3. 【小优化】golang中取两个字符串的公共前缀的长度

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 在VM的merge部分的代码中发现这样一个函数: func ...

  4. 6.2 Windows驱动开发:内核枚举SSSDT表基址

    在Windows内核中,SSSDT(System Service Shadow Descriptor Table)是SSDT(System Service Descriptor Table)的一种变种 ...

  5. Python RE 正则表达式模块

    正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex.regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为&qu ...

  6. 群联预告满血PCIe 5.0 SSD主控:飙上14.7GB/s

    群联电子将在CES 2024上展示两款新的PCIe 5.0 SSD主控方案,一个定位旗舰,一个面向主流. PCIe 5.0 SSD诞生已经差不多一年了,但是受限于群联E26主控的先天不足,以及闪存技术 ...

  7. 大数据生态组件WEB UI地址汇总

    (1) Hadoop Web UI http://master-1:50070/dfshealth.html#tab-overview (2) YARN应用Web UI http://master-1 ...

  8. spring前导知识-Tomcat、Maven等配置

    spring前导知识: 版本注意: 该博客所用的版本: tomcat version 9 (注意10有未知错误(个人测试)) Maven version3.6.3 (注意3.6.2未知错误) serv ...

  9. 从零开始的react入门教程(三),了解react事件与使用注意项

    壹 ❀ 引 在从零开始的react入门教程(二),从react组件说到props/state的联系与区别一文中,我们介绍了react组件的基本用法以及props与state的区别.其中react组件分 ...

  10. NC16697 [NOIP2001]Car的旅行路线

    题目链接 题目 题目描述 又到暑假了,住在城市A的Car想和朋友一起去城市B旅游.她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中 ...