Wiggle Subsequence

18 篇文章 0 订阅
11 篇文章 0 订阅
一. Wiggle Subsequence

A sequence of numbers is called a wiggle sequence if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a wiggle sequence.

For example, [1,7,4,9,2,5] is a wiggle sequence because the differences (6,-3,5,-7,3) are alternately positive and negative. In contrast, [1,4,7,2,5] and [1,7,4,5,5] are not wiggle sequences, the first because its first two differences are positive and the second because its last difference is zero.

Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, leaving the remaining elements in their original order.

Examples:

Input: [1,7,4,9,2,5]
Output: 6
The entire sequence is a wiggle sequence.

Input: [1,17,5,10,13,15,10,5,16,8]
Output: 7
There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].

Input: [1,2,3,4,5,6,7,8,9]
Output: 2

Follow up:
Can you do it in O(n) time?

Difficulty:Medium

TIME:TIMEOUT

解法一

这道题是求最长的锯齿状的子序列,当然看到最长,首先想到的就是动态规划。这道题动态规划的思想和求最长递增子序列十分相似。
如果采用 minus 数组表示以这个点作为锯齿子序列最低点结束的最长长度,采用 plus 数组表示以这个点作为锯齿子序列最高点结束的最长长度,而且令 X=<x1,x2,...,xi1,xi> 为带求解序列的的任意一个前缀,其中 0<j<i ,这道题的最优子结构可以描述为:

  • 如果 xi>xj ,那么 plus[i]=max(plus[i]minus[j]+1)
  • 如果 xi<xj ,那么 minus[i]=max(minus[i]plus[j]+1)

代码如下:

int wiggleMaxLength(vector<int>& nums) {
    if(nums.size() < 2)
        return nums.size();
    vector<int> minus(nums.size(),1);
    vector<int> plus(nums.size(),1);
    for(size_t i = 1; i < nums.size(); i++) {
        for(int j = 0; j < i; j++) {
            if(nums[i] > nums[j])
                plus[i] = max(plus[i], minus[j] + 1);
            if(nums[i] < nums[j])
                minus[i] = max(minus[i], plus[j] + 1);
        }

    }
    return max(plus[nums.size() - 1],minus[nums.size() - 1]);
}

代码的时间复杂度为 O(n2)

解法二

正如Follow up提示的一样,这道题存在着O(n)的解法。如果还有解法能比动态规划还要快的,那应该就是贪心算法了。
这里采用的贪心策略和求最长递增子序列类似,但还是有些差别的,起码复杂度比求最长递增子序列还要低。
这里的贪心策略简单来说就是保证锯齿的幅度最大化,比如给定序列 <1,4,9,5,2,3> <script type="math/tex" id="MathJax-Element-10"><1,4,9,5,2,3></script>,如果采用贪心算法,那么求得的最长锯齿状的序列变化如下:

  • <1,4> 初始化为两个数字
  • <1,9> 发现9比4大,那么保证锯齿幅度最大,把4替换为9
  • <1,9,5> 发现5比9小,加上5
  • <1,9,2> 发现2比5小,保证锯齿幅度最大,把5替换为2
  • <1,9,2,3> 发现3比2大,加上3,这就是这个序列的最长锯齿状序列

代码如下:

int wiggleMaxLength(vector<int>& nums) {
    if(nums.size() < 2)
        return nums.size();
    vector<int> v{nums[0]};
    for(int i = 1; i < nums.size(); i++) {
        if(nums[i] == nums[i - 1]) //跳过相同数字
            continue;
        if(v.size() == 1) { //初始化为两个数字的数组
            v.push_back(nums[i]);
            continue;
        }
        int dis = v.back() - v[v.size() - 2];
        if((nums[i] <= v.back() && dis < 0) || (nums[i] >= v.back() && dis > 0))
            v[v.size() - 1] = nums[i];
        else 
            v.push_back(nums[i]);
    } 
    return v.size();
}

代码的时间复杂度为O(n)。

总结

很多题能用动态规划来求解,但不一定能用贪心策略来求解。不过一般情况下,贪心策略都要比动态规划的时间复杂度要低(动态规划在求最优解的过程中求了很多无关的解,而贪心只求最优解)。

知识点
动态规划
贪心策略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值