LeetCode 每日一题376. 摆动序列

376. 摆动序列

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

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

进阶:

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

方法一:贪心

先说下为什么用 stack,当然 list 也可以,因为我看错题了,以为要返回结果集~。

  • 如果当前数字大于上一个数:
    1. 前面是上坡,那么当前的坡更陡,删除上一个数字,加入当前数字,状态依然为上坡
    2. 前面是下坡,加入当前数字,状态改为上坡
  • 如果当前数字小于上一个数:
    1. 前面是上坡,加入当前数字,状态更新为下坡
    2. 前面是下坡,那么当前更低,删除上一个数字,加入当前数字,状态依然为下坡
  • 返回容器长度
public int wiggleMaxLength(int[] nums) {
    int n = nums.length;
    if (n < 2) {
        return n;
    }
    Stack<Integer> stack = new Stack<>();
    stack.add(nums[0]);
    int status = 0;// 0初始化 1最后是下降 2最后是上升
    for (int i = 1; i < n; ++i) {
        if (nums[i] == stack.peek()) {
            continue;
        }
        if (status == 0) {
            status = nums[i] > stack.peek() ? 2 : 1;
        } else if (status == 1) {
            if (nums[i] > stack.peek()) {
                status = 2;
            } else {
                stack.pop();
            }
        } else {
            if (nums[i] > stack.peek()) {
                stack.pop();
            } else {
                status = 1;
            }
        }
        stack.push(nums[i]);
    }
    return stack.size();
}

方法二:动态规划

状态表达式:

  • up[i] 表示第 i 个数为上坡时摆动序列的最大长度
  • down[i] 表示第 i 个数为下坡时摆动序列的最大长度

状态转移:

  • 当前数字大于上一个数时,本次为上坡

    1. 上坡状态 up[i],可以从上一次的上坡状态up[i - 1] 和上一次的下坡状态[i - i] + 1 的较大者转移过来
    2. 下坡状态保持不变,即 down[i] = down[i - 1]
  • 当前数字小于上一个数时,本次为下坡

    1. 下坡状态 down[i],可以从上一次的下坡状态 down[i - 1] 和 上一次的上坡状态up[i - 1] + 1 的较大者转移过来
    2. 上坡状态保持不变,即 up[i] = up[i - 1]
  • 当前数字等于上一个数,上坡状态 up[i] = up[i - 1];下坡状态 down[i] = down[i - 1]

public int wiggleMaxLength(int[] nums) {
    int n = nums.length;
    if (n < 2) {
        return n;
    }

    int[] up = new int[n];
    int[] down = new int[n];
    up[0] = 1;
    down[0] = 1;

    for (int i = 1; i < n; ++i) {
        if (nums[i] > nums[i - 1]) {
            up[i] = Math.max(up[i - 1], down[i - 1] + 1);
            down[i] = down[i - 1];
        } else if (nums[i] < nums[i - 1]) {
            down[i] = Math.max(down[i - 1], up[i - 1] + 1);
            up[i] = up[i - 1];
        } else {
            up[i] = up[i - 1];
            down[i] = down[i - 1];
        }
    }
    return Math.max(up[n - 1], down[n - 1]);
}

执行结果

在这里插入图片描述

你可能感兴趣的:(每日一题,leetcode,java,算法,动态规划,贪心算法)