「手把手帶你學演算法」本週小結!(貪心演算法系列三)

程式碼隨想錄發表於2020-12-18

本文 https://github.com/youngyangyang04/leetcode-master 已經收錄,裡面還有leetcode刷題攻略、各個型別經典題目刷題順序、思維導圖,可以fork到自己倉庫,有空看一看一定會有所收穫,如果對你有幫助也給一個star支援一下吧!

本週開始恢復了題目系列。

對於貪心,大多數同學都會感覺,不就是常識嘛,這算啥演算法,那麼本週的題目就可以帶大家初步領略一下貪心的巧妙,貪心演算法往往妙的出其不意。

週一

貪心演算法:加油站中給出每一個加油站的汽油和開到這個加油站的消耗,問汽車能不能開一圈。

這道題目咋眼一看,感覺是一道模擬題,模擬一下汽車從每一個節點出發看看能不能開一圈,時間複雜度是O(n^2)。

即使用模擬這種情況,也挺考察程式碼技巧的。

for迴圈適合模擬從頭到尾的遍歷,而while迴圈適合模擬環形遍歷,對於本題的場景要善於使用while!

如果程式碼功力不到位,就模擬這種情況,可能寫的也會很費勁。

本題的貪心解法,我給出兩種解法。

對於解法一,其實我並不認為這是貪心,因為沒有找出區域性最優,而是直接從全域性最優的角度上思考問題,但思路很巧妙,值得學習一下。

對於解法二,貪心的區域性最優:當前累加rest[j]的和curSum一旦小於0,起始位置至少要是j+1,因為從j開始一定不行。全域性最優:找到可以跑一圈的起始位置。

這裡是可以從區域性最優推出全域性最優的,想不出反例,那就試試貪心。

解法二就體現出貪心的精髓,同時大家也會發現,雖然貪心是常識,有些常識並不容易,甚至很難!

週二

貪心演算法:分發糖果中我們第一次接觸了需要考慮兩個維度的情況。

例如這道題,是先考慮左邊呢,還是考慮右邊呢?

先考慮哪一邊都可以! 就別兩邊一起考慮,那樣就把自己陷進去了

先貪心一邊,區域性最優:只要右邊評分比左邊大,右邊的孩子就多一個糖果,全域性最優:相鄰的孩子中,評分高的右孩子獲得比左邊孩子更多的糖果

如圖:
135.分發糖果

接著在貪心另一邊,左孩子大於右孩子,左孩子的糖果就要比右孩子多。

此時candyVec[i](第i個小孩的糖果數量,左孩子)就有兩個選擇了,一個是candyVec[i + 1] + 1(從右孩子這個加1得到的糖果數量),一個是candyVec[i](之前比較右孩子大於左孩子得到的糖果數量)。

那麼第二次貪心的區域性最優:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果數量,保證第i個小孩的糖果數量即大於左邊的也大於右邊的。全域性最優:相鄰的孩子中,評分高的孩子獲得更多的糖果。

區域性最優可以推出全域性最優。

如圖:
135.分發糖果1

週三

貪心演算法:檸檬水找零中我們模擬了買檸檬水找零的過程。

這道題目剛一看,可能會有點懵,這要怎麼找零才能保證完整全部賬單的找零呢?

但仔細一琢磨就會發現,可供我們做判斷的空間非常少!

美元10只能給賬單20找零,而美元5可以給賬單10和賬單20找零,美元5更萬能!

區域性最優:遇到賬單20,優先消耗美元10,完成本次找零。全域性最優:完成全部賬單的找零。

區域性最優可以推出全域性最優。

所以把能遇到的情況分析一下,只要分析到具體情況了,一下子就豁然開朗了。

這道題目其實是一道簡單題,但如果一開始就想從整體上尋找找零方案,就會把自己陷進去,各種情況一交叉,只會越想越複雜了。

週四

貪心演算法:根據身高重建佇列中,我們再一次遇到了需要考慮兩個維度的情況。

之前我們已經做過一道類似的了就是貪心演算法:分發糖果,但本題比分發糖果難不少!

貪心演算法:根據身高重建佇列中依然是要確定一邊,然後在考慮另一邊,兩邊一起考慮一定會蒙圈。

那麼本題先確定k還是先確定h呢,也就是究竟先按h排序呢,還先按照k排序呢?

這裡其實很考察大家的思考過程,如果按照k來從小到大排序,排完之後,會發現k的排列並不符合條件,身高也不符合條件,兩個維度哪一個都沒確定下來。

所以先從大到小按照h排個序,再來貪心k

此時區域性最優:優先按身高高的people的k來插入。插入操作過後的people滿足佇列屬性。全域性最優:最後都做完插入操作,整個佇列滿足題目佇列屬性。

區域性最優可以推出全域性最優,找不出反例,那麼就來貪心。

總結

「程式碼隨想錄」裡已經講了十一道貪心題目了,大家可以發現在每一道題目的講解中,我都是把什麼是區域性最優,和什麼是全域性最優說清楚。

雖然有時候感覺貪心就是常識,但如果真正是常識性的題目,其實是模擬題,就不是貪心演算法了!例如貪心演算法:加油站中的貪心方法一,其實我就認為不是貪心演算法,而是直接從全域性最優的角度上來模擬,因為方法裡沒有體現區域性最優的過程。

而且大家也會發現,貪心並沒有想象中的那麼簡單,貪心往往妙的出其不意,觸不及防!哈哈

下週依然還是貪心,敬請期待!

我是程式設計師Carl,可以找我組隊刷題,也可以在B站上找到我,本文leetcode刷題攻略已收錄,更多精彩演算法文章盡在公眾號:程式碼隨想錄,關注後就會發現和「程式碼隨想錄」相見恨晚!

循序漸進學演算法,認準「程式碼隨想錄」,Carl手把手帶你過關斬將!

「手把手帶你學演算法」本週小結!(貪心演算法系列三)

相關文章