刷题记录 贪心算法-3:376. 摆动序列

题目:376. 摆动序列

难度:中等

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

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

  • 相反,[1, 4, 7, 2, 5][1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列最长子序列的长度

示例 1:

复制代码
输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。

示例 2:

复制代码
输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

示例 3:

复制代码
输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

一、模式识别

1.贪心算法

这道题我一开始是完全不会做的,可能是因为该题涉及到极值点,所以被列入了贪心算法

局部最优解:删除前一个极值到现在这个极值之间的节点就有了新的极值

从局部到全局:对整个数组执行这个过程

反例:要是有就不用贪心算法了。。。

实现方式:缓存上一个符号相反的坡度,当下一个符号相反的坡度出现时计数并更新缓存坡度

2.动态规划:子序列问题

从题目类型:如果刷过动态规划看到子序列问题很容易想到动态规划

思路:dp数组分别缓存从头到当前num所有的极大值和极小值数量,

每到一个num更新dp数组对应元素数值,

极大值和极小值逐个数字交替更新,只有极大极小值交替出现才能实现累加

二.代码实现

1.贪心算法

代码逻辑是:缓存上一个符号相反的坡度,当下一个符号相反的坡度出现时计数并更新缓存坡度

写法一:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n
        preDiff, curDiff, result = 0, 0, 1
        for i in range(n - 1):
            curDiff = nums[i + 1] - nums[i]
            if (preDiff <= 0 and curDiff > 0) or (preDiff >= 0 and curDiff < 0):
                result += 1
                preDiff = curDiff
        return result

写法二:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n
        preDiff, curDiff, result = 0, 0, 1
        for i in range(n - 1):
            curDiff = nums[i + 1] - nums[i]
            if (preDiff <= 0 and curDiff > 0) or (preDiff >= 0 and curDiff < 0):
                result += 1
                preDiff = curDiff
        return result
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

为什么在判断坡度符号时 preDiff <= 0或preDiff >= 0以及中是闭区间?

由于preDiff的更新条件不包含curDiff == 0的情况,

所以闭区间是为了处理preDiff第一次更新前的情况,即边界条件:数组首尾两端

2.动态规划

思路:dp数组分别缓存从头到当前num所有的极大值和极小值数量,

每到一个num更新dp数组对应元素数值,

极大值和极小值逐个数字交替更新,只有极大极小值交替出现才能实现累加

写法一:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [[1, 1] for _ in range(n)]
        for i in range(n - 1):
            for j in range(i + 1):
                if nums[i + 1] > nums[i]:
                    dp[i + 1][0] = max(dp[j][0], dp[j][1] + 1)
                if nums[i + 1] < nums[i]:
                    dp[i + 1][1] = max(dp[j][1], dp[j][0] + 1)
        return max(dp[-1][0], dp[-1][1])

写法二:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        dp = []
        for i in range(n - 1):
            dp.append([1, 1])
            for j in range(i + 1):
                if nums[i + 1] > nums[i]:
                    dp[i + 1][0] = max(dp[i][0], dp[j][1] + 1)
                if nums[i + 1] < nums[i]:
                    dp[i + 1][1] = max(dp[i][1], dp[j][0] + 1)
        return max(dp[-1][0], dp[-1][1])
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n)

3.优化版的动态规划

dp数组从前到后一定单调递增,所以往回找dp值的步骤是多余的:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        up = down = 1
        for i in range(n - 1):
            if nums[i + 1] > nums[i]:
                up = down + 1
            if nums[i + 1] < nums[i]:
                down = up + 1
        return max(up, down)
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
相关推荐
不太可爱的叶某人2 小时前
【学习笔记】MySQL技术内幕InnoDB存储引擎——第5章 索引与算法
笔记·学习·mysql
FreakStudio2 小时前
一文速通 Python 并行计算:13 Python 异步编程-基本概念与事件循环和回调机制
python·pycharm·协程·多进程·并行计算·异步编程
黑听人3 小时前
【力扣 困难 C】329. 矩阵中的最长递增路径
c语言·leetcode
豌豆花下猫4 小时前
让 Python 代码飙升330倍:从入门到精通的四种性能优化实践
后端·python·ai
夏末蝉未鸣014 小时前
python transformers库笔记(BertForTokenClassification类)
python·自然语言处理·transformer
YuTaoShao5 小时前
【LeetCode 热题 100】141. 环形链表——快慢指针
java·算法·leetcode·链表
巴伦是只猫6 小时前
【机器学习笔记 Ⅲ】4 特征选择
人工智能·笔记·机器学习
霖檬ing6 小时前
K8s——配置管理(1)
java·贪心算法·kubernetes
小小小新人121236 小时前
C语言 ATM (4)
c语言·开发语言·算法
不爱说话的采儿6 小时前
UE5详细保姆教程(第四章)
笔记·ue5·游戏引擎·课程设计