LeetCode刷題 貪心演算法 376擺動序列

2021-10-07 21:36:49 字數 3836 閱讀 5264

leetcode刷題|貪心演算法|#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

貪婪演算法(貪心演算法)是指在對問題進行求解時,在每一步選擇中都採取最好或者最優(即最有利)的選擇,從而

希望能夠導致結果是最好或者最優的演算法

貪婪演算法所得到的結果不一定是最優的結果(有時候會是最優解),但是都是相對近似(接近)最優解的結果

class

solution

int precha=nums[1]

-nums[0]

;//求前兩個數的差值

int count=precha==0?

1:2;

//如果前兩個數相等,則cout從1開始計,如果不相等,則count從2開始計

for(

int i=

2;ireturn count;

}}

複雜度分析

回溯演算法就是把問題的解空間轉化為圖或樹的結構表示,然後使用深度優先搜尋策略進行遍歷,遍歷的過程中記錄和尋找所有可行解或者最優解。

基本思想類同於:圖的深度優先搜尋和二叉樹的後序遍歷

應用:當問題是要求滿足某種性質(約束條件)的所有解或最優解時,往往使用回溯法。它有「通用解題法」之美譽。

實現(遞迴 和遞推(迭代)):

回溯法的實現方法有兩種:遞迴和遞推(也稱迭代)。一般來說,乙個問題兩種方法都可以實現,只是在演算法效率和設計複雜度上有區別。【模擬於圖深度遍歷的遞迴實現和非遞迴(遞推)實現】

遞迴思路簡單,設計容易,但效率低,其設計正規化如下:

//針對n叉樹的遞迴回溯方法  

void backtrack (

int t)

}

2、遞推

演算法設計相對複雜,但效率高。

//針對n叉樹的迭代回溯方法  

void iterativebacktrack ()}

}else

//不存在子節點,返回上一層

}}

詳解:

我們去找所有可能擺動子串行的長度並找到它們中的最大值。為了實現這樣的演算法,我們需要乙個回溯函式,calculate(nums, index, isup),將 nums 作為輸入陣列,index 記錄的是我們從哪個位置開始找最長擺動序列, boolean 變數 isup 記錄的是現在要找的是上公升元素還是下降元素。如果函式 calculate 在乙個上公升擺動之後被呼叫,我們需要用這個相同的函式找到下降的元素。如果 calculate 在乙個下降元素之後被呼叫,那麼我們需要用這個函式找到下乙個上公升的元素。

public

class

solution

return maxcount;

}public

intwigglemaxlength

(int

nums)

}

複雜度分析

時間複雜度: o(n!) 。calculate() 會被呼叫 n! 次。

空間複雜度: o(n)。回溯深度為 n 。

為了更好地理解這一方法,用兩個陣列來 dp ,分別記作 upup 和 downdown 。

每當我們選擇乙個元素作為擺動序列的一部分時,這個元素要麼是上公升的,要麼是下降的,這取決於前乙個元素的大小。

up[i] 存的是目前為止最長的以第 i個元素結尾的上公升擺動序列的長度。

類似的, down[i] 記錄的是目前為止最長的以第 i 個元素結尾的下降擺動序列的長度。

我們每當找到將第 ii 個元素作為上公升擺動序列的尾部的時候就更新 up[i] 。現在我們考慮如何更新 up[i],我們需要考慮前面所有的降序結尾擺動序列,也就是找到 down[j],滿足jnums[j] 。類似的,down[i] 也會被更新。

public

class

solution

else

if(nums[i]

< nums[j])}

}return

1+ math.

max(down[nums.length -1]

, up[nums.length -1]

);}}

複雜度分析

陣列中的任何元素都對應下面三種可能狀態中的一種:

上公升的位置,意味著 nums[i] > nums[i - 1]nums[i]>nums[i−1]

下降的位置,意味著 nums[i] < nums[i - 1]nums[i]更新的過程如下:

如果 nums[i]>nums[i−1] ,意味著這裡在擺動上公升,前乙個數字肯定處於下降的位置。所以 up[i]=down[i−1]+1 , down[i] 與 down[i−1] 保持相同。

如果 nums[i]如果 nums[i]==nums[i−1] ,意味著這個元素不會改變任何東西因為它沒有擺動。所以 down[i] 與 up[i] 與down[i−1] 和 up[i−1] 都分別保持不變。

最後,我們可以將 up[length−1] 和down[length−1] 中的較大值作為問題的答案,其中 length 是給定陣列中的元素數目。

class

solution

int[

] up=

newint

[nums.length]

;int

down=

newint

[nums.length]

; up[0]

=down[0]

=1;//只要有乙個元素,那就有乙個長度是擺動子序

for(

int i=

1;i)else

if(nums[i]

)else

}//此時up和down最後乙個元素就是累積下來的最大元素

return math.

max(up[nums.length-1]

,down[nums.length-1]

);}}

基於第三種方法改進,我們可以發現我們只需要up和down的最後乙個元素。因此我們不採用陣列,來節約空間

class

solution

int upcount=1;

int downcount=1;

for(

int i=

1;i)else

if(nums[i]

)}return math.

max(upcount,downcount);}

}

複雜度分析

LeetCode刷題指南 貪心演算法

45.跳躍遊戲 ii class solution maxl nextmax return 0 134.加油站 第一種解法 比較容易理解,但是效率比較低 class solution return rest 0 1 start 621.任務排程器 給定乙個用字元陣列表示的 cpu 需要執行的任務列表...

貪心演算法刷題

牛牛有乙個陣列array,牛牛可以每次選擇乙個連續的區間,讓區間的數都加1,他想知道把這個陣列變為嚴格單調遞增,最少需要操作多少次?嚴格遞增,我們應該讓某個數字後面的乙個比他小的連續區間都進行加1操作,然後遍歷整個陣列 除最後乙個數字 其實我們不需要真正的對陣列進行加1操作,只需要求出ai與ai 1...

Leetcode刷題系列(六)貪心演算法

在某乙個標準下,優先考慮最滿足標準的樣本,最後考慮最不滿足標準的樣本,最終得到乙個答案的演算法,叫作貪心演算法。也就是說,不從整體最優上加以考慮,所做出的是在某種意義上的區域性最優解。如何從區域性最優達到全域性最優解?舉反例和對數器來進行證明。對於給定的糖果和孩子胃口,看能最多滿足多少孩子。解題思路...