Leetcode刷题笔记 376. 摆动序列

376. 摆动序列

时间:2020年12月14日
知识点:贪心、动态规划
题目链接:https://leetcode-cn.com/problems/wiggle-subsequence/

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

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

解法
贪心

  1. 我这里先想到的是贪心 自己先模拟一遍
  2. 我们对于摆动顺序 如果是上升序列 我们要找之后是上升的中最大的数 为后面添加更多的可能性
  3. 对于下降也是 我们找下降的最小那个 可以用while去找
  4. 只需要遍历一次数组 记录上一个是什么 如果当前比上一个小 说明处于下降 找最小的那个 更新
  5. 上升的时候也同理 注意相等的情况 也要继续往后找

动态规划

  1. 动态规划的角度去找
  2. 定义两个数组 一个用来标记最后两个数字递增的最长摆动序列长度 as up 一个标记最后两个数字递减的最长摆动序列长度 as down
  3. 比如 1 3 2 4 是一个上升摆动序列 1 3 4 2是一个下降摆动序列
  4. 最终要的是如何更新这两个摆动序列呢
  5. 我们希望的是遍历一遍就可以得到答案 我们需要和上一个数字做对比
  6. 如果 上一个数字 >= 当前数字 如 1 17 5 和 1 17 5 4
    1. 上升序列 = 上一个上升序列的结果 如 1 17 5
    2. 下降序列 = max(上一个上升结果+1 也就新的结果 , 上一个下降结果) 如 1 17 5 4
  7. 如果 上一个数字 < 当前数字 如 1 17 4 5和 1 17 18
    1. 上升序列 = max(上一个下降结果+1 , 上一个上升结果) 如 1 17 4 5
    2. 下降序列 = 上一个下降序列 如 1 17 18
实例2  [1,17,5,10,13,15,10,5,16,8]
   up  1 2  2  4  4  4  4 4  6 6
  down 1 1  3  3  3  3  5 5  5 7
  1. 注意状态压缩
  2. 最大上升序列个数 和 最大下降个数 绝对值不超过1 不可能两个连续增加

代码

#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
/*
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size() == 0)
            return 0;
        int pre = nums[0],ans = 1;
        int i = 1;
        while(i < nums.size()){
            if(pre < nums[i]){
                while(i < nums.size() && pre <= nums[i]){
                    pre = nums[i];
                    i++;
                }
                ans++;
            }
            else if(pre > nums[i]){
                while(i < nums.size() && pre >= nums[i]){
                    pre = nums[i];
                    i++;
                }
                ans++;
            }
            else
                i++;
        }
        return ans;
    }
};*/
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) {
            return n;
        }
        int up = 1, down = 1;
        for (int i = 1; i < n; i++){
            if (nums[i] > nums[i - 1]){
                up = max(up, down + 1);// up = down + 1;
            } else if (nums[i] < nums[i - 1]){
                down = max(up + 1, down); //down = up + 1;
            }
        }
        return max(up, down);
    }
};
int main()
{
    vector<int> nums{1,17,5,10,13,15,10,5,16,8};
    Solution s;
    cout<<s.wiggleMaxLength(nums)<<endl;
    return 0;
}

今天也是爱zz的一天哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值