题目描述

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

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

题解

这题题面说的啰里啰唆的,其实就一句话:给你一个序列,找出最长的一个子序列,其中子序列相邻两个数的大小是波形的(也就是大小大小大等等这样的)。

暴力法

用 dfs 枚举所有可能的子序列,然后看最长的是多少,这种方法显然会超时。

动态规划

其实看到这道题,我第一个想到了最长上升子序列,这不就变了个形式嘛,于是动态规划解法直接就有了。

表示以
结尾的符合条件的最长子序列长度,其中 s 取 1 表示在
处子序列上升,取 0 表示下降。那么我们只需要遍历之前的所有 j ,如果
,那么在 j 处必须是要下降的,更新:

如果

,那么在 j 处必须是要上升的,更新:

然后取数组中最大值就是答案了,时间复杂度

动态规划+时间优化

换个定义,用

表示
之前的最长子序列,注意和上面的区别就是不一定以
结尾了。 s 取 1 表示最后两个数是上升的,取 0 表示最后两个数是下降的。

这里分为几种情况:

  • :
    • 考虑

      ,也就是最后两个数下降的,那肯定不能取
      ,因为
      比它更小、更优,所以直接更新为
    • 考虑
      ,也就是最后两个数上升的,那如果不取
      ,那更新为
      ;如果取的话,我们就要保证 i-1 之前最后两个数是下降的,并且之前的最后一个数小于
      。我们可以证明, i-1 之前的最后两个下降的数一定满足:第二个数
      是小于
      的,因为如果
      ,那么 j 到 i 之间的数一定是单调下降的,否则存在更长的子序列,那么就和
      矛盾了。综上,取的话
      更新为
  • : 同样考虑最后两个数上升还是下降,分析和上面一样。

综上考虑,时间复杂度可以降为

,空间复杂度是

动态规划+空间优化

在上面优化的基础上,我们还可以观察到,每一次

其实只会用到
,所以我们只需要保存当前和前一时刻的状态就行了,空间复杂度可以降为

贪心法

其实这题还可以直接贪心做,考虑一段连续的上升序列,最优子序列一定是包括了首尾两个数的,因为首是最小的数,选了它才能给前一个数留出更大的上升空间,而尾是最大的数,选了它才能给下一个数留出更多的下降空间。

所以我们贪心的扫描一遍数组,遇到上升或者下降的转折点就选取这个数。而如果数组不升不降,也就是不变的话,就不用管它,因为这些相同的数里面只需要选取一个就行了。

时间复杂度是

,空间复杂度是

代码

动态规划(c++)

class Solution {public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();if (n <= 1) return n;int dp[n][2], res = 1;memset(dp, 0, sizeof dp);dp[0][0] = dp[0][1] = 1;for (int i = 1; i < n; ++i) {for (int j = 0; j < i; ++j) {if (nums[j] != nums[i]) {int s = nums[j] < nums[i];dp[i][s] = max(dp[i][s], dp[j][s^1]+1);}}res = max(res, dp[i][0]);res = max(res, dp[i][1]);}return res;}
};

动态规划+时间优化(c++)

class Solution {public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();if (n <= 1) return n;int dp[n][2];memset(dp, 0, sizeof dp);dp[0][0] = dp[0][1] = 1;for (int i = 1; i < n; ++i) {if (nums[i] == nums[i-1]) {dp[i][0] = dp[i-1][0];dp[i][1] = dp[i-1][1];} else {int s = nums[i] > nums[i-1];dp[i][s] = max(dp[i-1][s], dp[i-1][s^1] + 1);dp[i][s^1] = dp[i-1][s^1];}}return max(dp[n-1][0], dp[n-1][1]);}
};

动态规划+空间优化(c++)

class Solution {public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();if (n <= 1) return n;int dp[2][2];memset(dp, 0, sizeof dp);dp[0][0] = dp[0][1] = 1;for (int i = 1; i < n; ++i) {if (nums[i] == nums[i-1]) {dp[1][0] = dp[0][0];dp[1][1] = dp[0][1];} else {int s = nums[i] > nums[i-1];dp[1][s] = max(dp[0][s], dp[0][s^1]+1);dp[1][s^1] = dp[0][s^1];swap(dp[0][s], dp[1][s]);swap(dp[0][s^1], dp[1][s^1]);}}return max(dp[0][0], dp[0][1]);}
};

贪心(c++)

class Solution {public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();if (n <= 1) return n;int res = 1, pre_ord = -1;for (int i = 1; i < n; ++i) {if (nums[i] == nums[i-1]) continue;int ord = nums[i] > nums[i-1];if (ord != pre_ord) res++;pre_ord = ord;}return res;}
};

后记

鼠年快乐,新年献给大家的第一道题,尽量写的详细一点。

官方题解没有严谨的证明,虽然方法也是这 5 种,但是没有说清楚,不能令人信服。

序列复杂度怎么看_每日算法系列【LeetCode 376】摆动序列相关推荐

  1. 重复次数最多的 子串_每日算法系列【LeetCode 424】替换后的最长重复字符

    题目描述 给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次.在执行上述操作后,找到包含重复字母的最长子串的长度. 示例1 输入: s = &quo ...

  2. 【LeetCode每日一题】——376.摆动序列

    文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[解题思路] 七[题目提示] 八[题目进阶] 九[时间频度] 十[代码实现] 十一[提交结果] 一[题目类别 ...

  3. LeetCode 376. 摆动序列 中等难度

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

  4. leetcode 376. 摆动序列 思考分析

    目录 题目 思路分析 代码 总结 题目 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列.第一个差(如果存在的话)可能是正数或负数.少于两个元素的序列也是摆动序列. 例如, [1 ...

  5. leetcode - 376. 摆动序列

    376. 摆动序列 -------------------------------------------- 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列.第一个差(如果存在 ...

  6. 序列复杂度怎么看_《趣学算法》作者又一力作上架,再分享您一篇算法复杂度...

    不知道读者们有没有看过陈小玉的<趣学算法>这本书,该书在出版后受到广大读者一致好评,在一年内重印了10次,并输出了繁体版的版权.不知道读过这本书的朋友们感觉第一本怎么样?欢迎留言给我们.接 ...

  7. 找出最具竞争力的子序列_每日算法系列【LeetCode 376】摆动序列

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

  8. 摆动序列算法C语言,376 摆动序列 leetcode

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

  9. leetcode 376. 摆动序列(dp)

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

最新文章

  1. ●观光(17.12.02多校联测题目)
  2. 阿里钉钉,马云旗下的又一个千亿美金产品?
  3. 帧同步_什么是帧同步什么是状态同步
  4. 树莓派 rtl8188eu 芯片wifi驱动
  5. 因为犯罪被判三年刑,期间没办法还信用卡,银行会怎么做?
  6. 郑州it java_郑州Java网站开发
  7. Exchange 企业邮件与Windows安全应用 — Exchange 2007 收件人管理
  8. wordpress 后台404解决办法
  9. Clojure 学习入门(2)- eclipse 插件
  10. ege和c语言做贪吃蛇,新萌 求大神给一个 EGE做的贪吃蛇代码 带注释的 没注释的看不懂...
  11. Deepin 20.5 安装nvidia驱动
  12. Python3遇到问题unicodeescape codec cant decode bytes in position 2 3 truncated UXXXXXXXX escape解决办法
  13. Spring Security实现用户名密码验证的原理
  14. 整理10类Java毕设练手项目,献给帅帅的计算计专业毕业人
  15. NIOS 外存 SDRAM(华邦 W9864G6KH)
  16. halcon-检测圆弧拟合圆
  17. 条码软件如何自定义条码二维码的样式
  18. 教育:构造主义和机能主义
  19. win7--svchost占用内存过大
  20. LVS模式一:DR模式(ipvsadm)

热门文章

  1. 冲刺阶段(二) 第六天
  2. 第一次冲刺团队绩效评估
  3. 博客园上海地区活动——LinkCoder主题社区第二期:淘宝服务化架构的设计和实践...
  4. 【2010】asp.net GridView分页的实现
  5. 55 - 算法 -动态规划 -数塔问题 感觉都是数组建模 递推方法规则
  6. html文档不是本地电脑,电脑浏览器打不开本地html文件
  7. 计算机网络技术之城域网与三网融合技术
  8. Python稳基修炼之计算机等级考试易错概念题2(含答案与解析)
  9. 初学者phthon笔记(异常处理)
  10. P5708 【深基2.习2】三角形面积【入门题】