最近開始學習王爭老師的《資料結構與演算法之美》,通過總結再加上自己的思考的形式記錄這門課程,文章主要作為學習歷程的記錄。
首先來看乙個例子,假設我們有乙個可以容納100kg物品的揹包
為了使揹包中所裝物體的總價值最大,如何選擇在揹包中裝哪些豆子?這個問題的解決是將單價從高到低排列,它的本質借助的是貪心演算法。
總結一下貪心演算法解決問題:
第一步,當我們看到這類問題時,首先要聯想到貪心演算法。針對一組資料,我們定義了限制值和期望值,希望從中選出幾個資料,在滿足限制值的情況下,期望值最大。
第二步,我們嘗試看下這個問題是否可以用貪心演算法解決。每次選擇當前情況下,在對限制值同等貢獻量的情況下,對期望值貢獻最大的資料。
第三步,我們舉幾個例子看下貪心演算法產生的結果是否是最優的。大部分情況下,舉幾個例子驗證一下就可以了。
實際上,用貪心演算法解決問題的思路,並不總能給出最優解。舉個例子,在乙個有權圖中,從頂點s開始,找一條到頂點t的最短路徑(路徑中邊的權值和最小)。貪心演算法的解決思路是,每次都選擇一條跟當前頂點相連的權最小的邊,直到找到頂點t。
按照這個思路,我們求出的最短路徑是s-a-e-t,路徑長度是1+4+4=9.
但這種貪心的選擇方式,最終求得路徑並不是最短路徑,因為路徑s-b-d-t才是最短路徑,因為這條路徑的長度是2+2+2=6.在這個問題上,貪心演算法不工作的主要原因是前面的選擇會影響後面的選擇。即便第一步選擇最優的走法,但有可能因為這一步選擇,導致後面選擇都很糟糕。
1、分糖果
我們有m個糖果和n個孩子,m<n。要將糖果分給孩子吃,每個糖果的大小不等,這m個糖果的大小分別是s1、s2、s3、…、sm。除此之外,每個孩子對糖果大小的需求不一樣,只有糖果的大小大於等於孩子的對糖果大小的需求時,孩子才得到滿足假設這n個孩子對糖果大小需求為g1、g2、g3、…、gn,如何分配糖果才能滿足最多數量的孩子?
這個問題可以抽象成從n個孩子中,抽取一部分孩子分配糖果,讓滿足的孩子的個數最大。這個問題的限制值就是糖果個數m。
採用貪心演算法,我們可以從需求小的孩子開始分配糖果。因為滿足乙個需求大的孩子跟滿足乙個需求小的孩子,對期望值的貢獻是一樣的。我們每次從剩下的孩子中,找出對糖果大小需求最小的,然後發給他剩下的糖果中能滿足他的最小的糖果,這樣得到的分配方案,也就是滿足的孩子個數最多的方案。
以力扣455題為例,假設你是一位很棒的家長,想要給你的孩子們一些小餅乾。但是,每個孩子最多只能給一塊餅乾。對每個孩子 i ,都有乙個胃口值 gi ,這是能讓孩子們滿足胃口的餅乾的最小尺寸;並且每塊餅乾 j ,都有乙個尺寸 sj 。如果 sj >= gi ,我們可以將這個餅乾 j 分配給孩子 i ,這個孩子會得到滿足。你的目標是盡可能滿足越多數量的孩子,並輸出這個最大數值。(你可以假設胃口值為正。乙個小朋友最多只能擁有一塊餅乾。)
class solution(object):
def findcontentchildren(self, g, s):
num = 0
g = sorted(g)
s = sorted(s)
for ele in s:
if num=g[num]:
num+=1
return num
2、錢幣找零
假設我們有1元、2元、5元、10元、20元、50元、100元這些面額的紙幣,它們的張數分別是c1、c2、c5、c10、c20、c50、c100.現在要用這些錢來支付k元,最少要用多少張紙幣?
在貢獻相同期望值(紙幣數目)的情況下,我們希望多貢獻點金額。這樣可以讓紙幣數更少。
3、區間覆蓋
假設我們有 n 個區間,區間的起始端點和結束端點分別是 [l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。我們從這 n 個區間中選出一部分區間,這部分區間滿足兩兩不相交(端點相交的情況不算相交),最多能選出多少個區間呢?
這個問題的解決思路:假設這 n 個區間中最左端點是 lmin,最右端點是 rmax。這個問題就相當於,我們選擇幾個不相交的區間,從左到右將 [lmin, rmax] 覆蓋上。我們按照起始端點從小到大的順序對這 n 個區間排序。我們每次選擇的時候,左端點跟前面的已經覆蓋的區間不重合的,右端點又盡量小的,這樣可以讓剩下的未覆蓋區間盡可能的大,就可以放置更多的區間。
假設有1個包含1000個字元的檔案,每個字元佔1個byte(1個byte=8bit),儲存這1000個字元就一共需要8000bits,需要一種更節省空間的儲存方式。
假設通過統計這1000個字元只包含6個不同的字元,分別為a、b、c、d、e、f。若用3個二進位制位(bit)就可以表示8個不同字元,此時用3000個bits即可。
這時候霍夫曼編碼出現了。霍夫曼編碼可以更加節省空間。它不僅會考察文字中有多少個字元,還會考察每個字元出現的頻率。根據頻率的不同,選擇不同長度的編碼。
這時候,1000個字元只需要2100bits。
處理過程:我們把每個字元看作乙個節點,並且輔帶著把頻率放到優先順序佇列中。我們從佇列中取出頻率最小的兩個節點 a、b,然後新建乙個節點 c,把頻率設定為兩個節點的頻率之和,並把這個新節點 c 作為節點 a、b 的父節點。最後再把 c 節點放入到優先順序佇列中。重複這個過程,直到佇列中沒有資料。
我們給每一條邊加上畫乙個權值,指向左子節點的邊我們統統標記為 0,指向右子節點的邊,我們統統標記為 1,那從根節點到葉節點的路徑就是葉節點對應字元的霍夫曼編碼。
節點的路徑就是葉節點對應字元的霍夫曼編碼。
資料結構與演算法 貪心演算法
1 給定 n 種物品和乙個揹包,物品 i 的重量是 w i 其價值是 p i 揹包的容量為 c。設物品已按單位重量價值遞減的次序排序。每種物品不可以裝入揹包多次,但可以裝入部分的物品 i。揹包問題是選擇裝入揹包中的物品,在不超過揹包容量的前提下使揹包的得總價值最大。用貪心法設計與實現乙個演算法,求解...
資料結構與演算法 貪心演算法
定義每個古董重量 揹包問題 在對問題求解時,總是作出在當前看來是最好的選擇。也就是說,不從整體上加以考慮,它所作出的僅僅是在某種意義上的區域性最優解 是否是全域性最優,需要證明 有一天海盜們截獲了一艘裝滿各種各樣古董的貨船,每一件都價值連城,一旦打碎就是去了價值,海盜船載重量為c,每件固定的重量為w...
資料結構與演算法 貪心演算法
有如下場景 針對一組資料,我們定義了限制值和期望值,希望從中選出幾個資料,在滿足限制值的情況下,期望值最大。為了達到上述目的,貪心演算法是其中的乙個解決方案。例如,路徑選擇問題,從 s 城市至 e 城市,在只能路過 2 個城市的情況下,如何走的最短,如下圖所示 英文全稱 greedy algorit...