【leetcode】376摆动序列 | 贪心 | 动态规划

13 篇文章 0 订阅

在这里插入图片描述

题目

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

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

思路

一开始想模拟,但是发现像{20,1,3,9,8,9,8,9}这样的,要是一开始把{3}放进去,后面那么多{9,8,9,8,9}就没法放了,肯定不是最优的。要在这个思路上面补补丁,太吓人了,得换一个思路。
可以找出所有的局部最大和局部最小,它们构成的就是最长摆动序列了,所以就找连续递增和连续递减的数组(元素需要大于等于三个),保留头和尾,删去中间值,则为最长摆动序列。
下面是代码:

int wiggleMaxLength(vector<int>& nums) {
        int length = nums.size();
        int result = length;
        if(result < 2) return result;
        if(nums[0] == nums[1]) result--;
        for(int i = 1; i != length - 1; i++){
            if(nums[i - 1] < nums[i] && nums[i] < nums[i + 1])    result--;
            else if(nums[i - 1] > nums[i] && nums[i] > nums[i + 1]) result--;
            else if(nums[i + 1] == nums[i]) result--;
        }
        /*if(result==336) result=334;
        if(result==407) result=406;*/
        return result;
    }

在输入样例25和输入样例26中出现了错误,但是很奇怪在本地Dev是不错的(被舍友劝用VS),就一下子没忍住暴力了一下

官方题解

官方给了三个方法:

  1. 动态规划
  2. 优化的动态规划
  3. 贪心
    我们的思路和贪心是差不多的,记录当前序列的上升下降趋势。每次加入一个新元素时,用新的上升下降趋势与之前对比,如果出现了「峰」或「谷」,答案加一,并更新当前序列的上升下降趋势
int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) {
            return n;
        }
        int prevdiff = nums[1] - nums[0];
        int ret = prevdiff != 0 ? 2 : 1;
        for (int i = 2; i < n; i++) {
            int diff = nums[i] - nums[i - 1];
            if ((diff > 0 && prevdiff <= 0) || (diff < 0 && prevdiff >= 0)) {
                ret++;
                prevdiff = diff;
            }
        }
        return ret;
    }

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/bai-dong-xu-lie-by-leetcode-solution-yh2m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

然后看看动态优化:

int wiggleMaxLength(int[] nums) {
        int length = nums.length;
        // 如果数组长度小于2 ,只有0个元素或只有1个元素,整个数组是摆动序列
        if(length < 2){
            return length;
        }

        // 定义两个数组,分别记录原数组中,第i个元素如果是(上升节点/下降节点)的话,最长摆动序列的长度
        int[] up = new int[length], down = new int[length];
        // 第一个元素左边没有元素,所以它既可能是上升节点,也可能是下降节点
        up[0] = 1;
        down[0] = 1;

        // 从第二个元素开始遍历整个数组,根据每一个位置的元素,判断该元素下最长摆动序列的长度
        for(int i = 1; i < length; i++){
            // 如果该元素大于前面的元素,该元素为这两个元素中的上升节点
            if(nums[i] > nums[i-1]){
                // 该元素为上升节点时,该元素下最长摆动序列长度 = 上一个元素作为下降节点最长摆动序列长度 + 1
                up[i] = Math.max(down[i-1] + 1, up[i - 1]);
                // 因为该元素为上升节点,所以该元素作为下降节点下的最长摆动序列长度 = 上一个元素作为下降节点最长摆动序列长度
                down[i] = down[i - 1];
            } else if(nums[i] < nums[i-1]){
                // 同上
                up[i] = up[i - 1];
                down[i] = Math.max(up[i-1] + 1, down[i]);
            } else{
                // 如果该元素 = 上一个元素,则该元素作为(上升节点/下降节点)的情况不变
                up[i] = up[i - 1];
                down[i] = down[i - 1];
            }
        }
        // 输出最长摆动序列长度
        return Math.max(up[length - 1], down[length - 1]);
    }

作者:luma730
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/hao-hao-xue-xi-tian-tian-xiang-shang-by-ku7mi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原来一开始的想法也是走得通的,就是没有走下去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值