跳至主要內容

376, 摆动序列

Mike大约 3 分钟greedymediumarraygreedydynamic programming

一、题目描述

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

  • 例如,[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)时间复杂度完成此题?

相关主题

  • 贪心
  • 数组
  • 动态规划

二、题解

方法 1: 贪心

pub fn wiggle_max_length(nums: Vec<i32>) -> i32 {
    let len = nums.len();
    if len <= 1 {
        return len as i32;
    }

    let mut prev_diff = nums[1] - nums[0];
    let mut res = if prev_diff == 0 { 1 } else { 2 };
    for i in 2..len {
        let diff = nums[i] - nums[i - 1];
        if (diff > 0 && prev_diff <= 0) || (diff < 0 && prev_diff >= 0) {
            prev_diff = diff;
            res += 1;
        }
    }

    res
}

方法 2: 动态规划

pub fn wiggle_max_length(nums: Vec<i32>) -> i32 {
    let len = nums.len();
    if len <= 1 {
        return len as i32;
    }

    let (mut up, mut down) = (vec![0; len], vec![0; len]);
    (up[0], down[0]) = (1, 1);
    for i in 1..len {
        if nums[i - 1] < nums[i] {
            up[i] = std::cmp::max(up[i - 1], down[i - 1] + 1);
            down[i] = down[i - 1];
        } else if nums[i - 1] > nums[i] {
            up[i] = up[i - 1];
            down[i] = std::cmp::max(up[i - 1] + 1, down[i - 1]);
        } else {
            up[i] = up[i - 1];
            down[i] = down[i - 1];
        }
    }

    std::cmp::max(up[len - 1], down[len - 1])
}

方法 3: 优化的动态规划

pub fn wiggle_max_length(nums: Vec<i32>) -> i32 {
    let len = nums.len();
    if len <= 1 {
        return len as i32;
    }

    let (mut up, mut down) = (1, 1);
    for i in 1..len {
        if nums[i - 1] < nums[i] {
            up = std::cmp::max(up, down + 1);
        } else if nums[i - 1] > nums[i] {
            down = std::cmp::max(up + 1, down);
        }
    }

    std::cmp::max(up, down)
}