LeetCode-376-mid-摆动序列(贪心、动态规划、具体分析)

关键字: "贪心"、"动态规划"、"具体分析"

题目描述

在一个数组中选出相对大小交替的最长子序列。
LeetCode-376-mid-摆动序列

分析

  • 摆动序列:对于非边界点,是峰顶arr[i-1] < arr[i] > arr[i+1]或谷底arr[i-1] > arr[i] < arr[i+1]
  • 最长摆动序列个数有很多,但是最长摆动序列的长度受限。
  • 生成式地考虑:对于一个已有的摆动序列,在不知道数组中下一个值arr[i+1]的情况下,如果此摆动序列目前为末尾上升序列,则其最后一个值越大,将arr[i+1]附加在该上升摆动序列末尾形成新的下降摆动序列的概率就越大。

(与动态规划解这道题相比)总的来说,本题的最佳解题方式为贪心:计数拐点个数即可。

解题思路(贪心)

对于摆动序列,每次末尾值的选择,如果当前是上升摆动序列,且下一个值arr[i+1]比摆动序列最后一个值还要大,则将摆动序列的末尾值更新为arr[i+1],结果仍然保持为上升摆动序列且长度不增加。如果下一个值更小,则长度增加,转变为下降摆动序列。

即为在寻找序列的峰值和谷底数目。

算法

INPUT: nums[]
OUTPUT: maxLen

if nums.size() < 1 :
    return nums.size()

arr <- nums 去重

isUp = (nums[1]>nums[0])
count = 1
for i = 2 to arr.size():
    if (nums[i]>nums[i-1]) ^ isUp :
        isUp = !isUp
        count += 1
maxLen = count + 1
return maxLen

数据结构

不需要特殊的读写等功能,线性表遍历即可。

复杂度分析

时间复杂度:去重(O(n))+遍历球峰顶与谷底数目(O(n)) = O(n)

空间复杂度:O(n)

代码实现

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {

        //[0,0] 输出为1; 去除相邻重复
        if ( nums.size() < 1 )
            return 0 ;
        vector<int> arr ;
        arr.push_back( nums[0] ) ;
        for ( int i = 1 ; i < nums.size() ; ++ i ){
            if ( nums[i] == nums[i-1] ){
                continue ;
            }
            arr.push_back(nums[i]) ;
        }
        //count 为摆动次数
        if ( arr.size() < 2 ){
            return arr.size() ;
        }
        bool flag = (arr[1] > arr[0]) ;
        int count = 1;
        for ( int i = 2 ; i < arr.size() ; ++i ){
            if ( (arr[i] > arr[i-1]) ^ flag ){
                flag = !flag ;
                ++ count ;
            }
        }
        return count+1 ;
    }
};

解题思路(动态规划1)

up[i] 记录以i结尾的最长上升摆动序列
down[i] 记录以i结尾的最长下降摆动序列

对于k+1:
以k+1结尾的最长上升摆动序列:满足j < k+1且nums[j] < nums[k+1]的down[j] 的最大值+1产生
以k+1结尾的最长下降摆动序列:满足j < k+1且nums[j] > nums[k+1]的up[j] 的最大值+1产生

迭代公式:
up[i] = \begin{cases} 1 & i = 0 \\ max( down[0], down[1], ..., down[j], ..., down[i-1])+1 & nums[j]<nums[i] \end{cases}

迭代公式:
down[i] = \begin{cases} 1 & i = 0 \\ max( up[0], up[1], ..., up[j], ..., up[i-1])+1 & nums[j]>nums[i] \end{cases}

算法

INPUT: nums[]
OUTPUT: maxLen

if nums.size() < 1 :
    return nums.size()

arr <- nums 去重
up, down <- [1]

for i = 1 to arr.size() :
    for j = 0 to i-1 :
        if ( nums[i] > nums[j] )
            up[i] = max( up[i], down[j]+1 )
        if ( nums[i] < nums[j] )
            down[i] = max( down[i], up[j]+1 )

数据结构

不需要特殊的读写等功能,vector数组存储down[]和up[]即可。

复杂度分析

时间复杂度:去重(O(n))+遍历迭代(O(n^2))= O(n^2)

空间复杂度:O(n)

解题思路(动态规划2)

up[i] 记录前i个数中的最长上升摆动序列
down[i] 记录前i个数中的最长下降摆动序列

对于k+1:
前k+1个数中的最长上升摆动序列:若nums[k] < nums[k+1],则up[k+1]=max(up[k],down[k]+1); 否则 up[k+1] = up[k]
前k+1数中的最长下降摆动序列:若nums[k] > nums[k+1],则down[k+1]=max(down[k],up[k]+1); 否则 down[k+1] = down[k]

迭代公式:
up[i] = \begin{cases} max(up[i-1], down[i-1]+1) & nums[i] > nums[i-1] \\ up[i-1] & nums[i] <= nums[i-1] \end{cases}

down[i] = \begin{cases} max(down[i-1], up[i-1]+1) & nums[i] < nums[i-1] \\ down[i-1] & nums[i] >= nums[i-1] \end{cases}

算法

INPUT: nums[]
OUTPUT: maxLen

if nums.size() < 1 :
    return nums.size()

arr <- nums 去重
up, down <- [1]

for i = 1 to arr.size() :
    if arr[i] > arr[i-1] :
        up[i] = max(up[i-1], down[i-1]+1)
        down[i] = down[i-1]
    if arr[i] < arr[i-1] :
        up[i] = up[i-1] 
        down[i] = max(down[i-1], up[i-1]+1)

return max( up[-1], down[-1])

数据结构

不需要特殊的读写等功能,vector数组存储down[]和up[]即可。

复杂度分析

时间复杂度:去重(O(n))+遍历迭代(O(n))= O(n)

空间复杂度:O(n)

相关问题

LeetCode-300-mid-求最长上升子序列,这道题是使用动态规划来求解,但是在题面上很相似。
在摆动序列这道题中,有文章指出这一道题目。但是该题的动态规划算法对应这里给出动态规划1(本文的第二个算法)。第二个版本的动态规划实际上用了贪心的部分来减少计算量。


PS.

  1. 相比较于其他已有的leetcode刷题笔记,我希望能够提供相关的解题分析和部分相关问题的链接,使得大家能获得一个较好的分析与相关问题的比较。

  2. 偶尔会进行类似题目的总结工作,有需要的读者可以对这份工作进行关注。

  3. 如果你发现有相关的错误或者表述不当不清晰的地方,请进行评论,我会尽快进行核对勘正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容