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