leetcode
leetcode 351 ~ 400
摆动序列

摆动序列

难度:

标签:

题目描述

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

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

 

进阶:你能否用 O(n) 时间复杂度完成此题?

代码结果

运行时间: 17 ms, 内存: 16.1 MB


/*
 * 使用Java Stream实现的思路:
 * 1. 如果nums的长度小于2,直接返回nums的长度。
 * 2. 创建一个AtomicInteger来记录当前up的值,另一个记录down的值。
 * 3. 使用IntStream.range从1遍历到nums.length - 1。
 * 4. 在forEach中比较相邻元素的差值,更新up和down。
 * 5. 最后返回up和down中的最大值。
 */
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
 
public class Solution {
    public int wiggleMaxLength(int[] nums) {
        if (nums.length < 2) return nums.length;
        AtomicInteger up = new AtomicInteger(1);
        AtomicInteger down = new AtomicInteger(1);
        IntStream.range(1, nums.length).forEach(i -> {
            if (nums[i] > nums[i - 1]) {
                up.set(down.get() + 1);
            } else if (nums[i] < nums[i - 1]) {
                down.set(up.get() + 1);
            }
        });
        return Math.max(up.get(), down.get());
    }
}

解释

方法:

这个题解的思路是遍历数组,用一个变量 flag 来记录前一个差值的正负。如果当前差值和前一个差值符号相反,则摆动序列长度加1,并更新 last 为当前元素。如果当前差值和前一个差值符号相同,则只更新 last 为当前元素,不增加摆动序列长度。flag 初始为0,遇到第一个非0差值时,根据正负设置 flag 为1或-1。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到使用flag来记录前一个差值的正负,初始值为0。请问在什么情况下flag会保持为0,这是否影响算法的正确性和完整性?
在题解中,flag的初始值设为0,它会保持为0直到遇到第一个非0差值。如果数组中的所有元素相等或者数组只有一个元素,则整个遍历过程中,flag将始终为0。这种情况下,算法的逻辑是正确的,因为一个恒定的序列或单个元素的序列不具备摆动的特性,所以摆动序列的长度应该为1。因此,flag保持为0不会影响算法的正确性和完整性。
🦆
在题解的算法中,当连续出现多个相同的数字时,如何处理这些数字,它们是否会被计入摆动序列的长度?
在题解的算法中,当遇到连续的相同数字时,由于差值为0,所以不会更新res(摆动序列的长度)。这些数字在计算摆动序列时被视为一个元素处理,即在检测到差值变化前,连续的相同数字仅算作序列中的一个点。因此,这些连续相同的数字不会增加摆动序列的长度。
🦆
题解中提到当遇到第一个非0差值时,会根据差值的正负来设置flag。但在实际操作中,如何确保处理的是第一个非0差值,而不是之后的某个非0差值?
在算法实现中,flag初始设为0,并在遍历过程中只在遇到第一个非0差值时修改flag的值(从0变为1或-1)。一旦flag的值被设定后,它只会在遇到符号相反的差值时才会变更。因此,通过检查flag是否为0,我们可以确保只在第一次遇到非0差值时对其进行处理,后续的非0差值将根据当前flag值和差值的关系来处理,而不会重新设定flag。
🦆
在更新flag和last的逻辑中,题解似乎没有考虑到数组中所有元素都相同的情况。在这种特殊情况下,算法的输出是否正确?
如果数组中所有元素都相同,那么所有的差值都为0,flag将保持其初始值0,last将不断更新为相同的值,但res(摆动序列的长度)始终维持为1。这是正确的,因为一个全相同元素的数组不具备摆动性,其摆动序列的最大长度应为1。因此,算法在这种情况下的输出是正确的。

相关问题