【数据结构与算法】【算法思想】贪心算法
貪心算法
回溯算法
分治算法
動態(tài)規(guī)劃
四種基本的算法思想:貪心算法,分治算法,回溯算法,動態(tài)規(guī)劃,他們不是具體算法,常用來指導(dǎo)我們設(shè)計具體的算法和編碼等。
一:貪心算法有很多經(jīng)典應(yīng)用
霍夫曼編碼(Huffman Coding),Prim和Kruskal最小生成數(shù)算法,Dijkstra單源最短路徑算法。
二:如何理解“貪心算法”
假設(shè)我們有一個可容納100kg物品的背包,可以裝下各種物品,我們有以下5中豆子,每種豆子的總量和總價值都各不相同。為了讓背包中所裝物品的總價最大,該如何?
第一步:當我們看到這類問題時,首先要聯(lián)想到貪心算法:針對一組數(shù)據(jù),定義了限制值和期望值,系統(tǒng)從中選出幾個數(shù)據(jù),在滿足限制值的情況下,期望值最大。
第二步:嘗試看這個問題是否可以用貪心算法解決:每次選擇當前情況下,在對限制值同等貢獻量的情況下,對期望值貢獻最大的數(shù)據(jù)。
第三步:舉幾個例子看下貪心算法產(chǎn)生的結(jié)果是否最優(yōu)的。大部分情況下,舉幾個例子驗證一下就可以了。嚴格的證明貪心算法的正確性,非常復(fù)雜,需要涉及較多的數(shù)學推理。并且,從實踐的角度來說,大部分能用貪心算法的問題,貪心算法的正確性都是顯而易見的,月不需要嚴格的數(shù)學推導(dǎo)證明。
貪心算法,專注于當下最優(yōu),但可能無法取得全局最優(yōu)。
貪心算法實戰(zhàn)分析
一:分糖果
有m個糖果和n個孩子,但m<n,所以糖果只能分配給一部分孩子。
每個糖果的大小不等,分為s1,s2……sm。除此之外,每個孩子對糖果大小的需求也是不一樣的,只有糖果的大小>=孩子對糖果大小的需求分別是g1,g2,g3……gn。
如何分配才可能滿足最多數(shù)量的孩子?
可將這個問題抽象成:從n個孩子中抽取一部分孩子分配糖果,讓滿足的孩子個數(shù)(期望值)是最大的。這個問題的限制值就是糖果個數(shù)m。
對于一個孩子而言,如果小的糖果可以滿足,我們就沒必要用更大的糖果,這樣更大的就可以留給其他對糖果大小需求更大的孩子。另一方面,對糖果大小需求小的孩子更容易被滿足,所以,我們可以從需求小的孩子開始分配他糖果。因為滿足一個需求大的孩子跟滿足一個需求小的孩子,對我們期望值貢獻是一樣的。
二:錢幣找零(部分題目不適用 100 99 1 找396 )
假設(shè)有1元,2元,5元,10元,50元,100元這些面額的紙幣,他們的張數(shù)分別是c1,c2,c5,c10,c20,c50,c100。我們要有支付k元,最少要用多少張紙幣呢?
在貢獻相同期望值(紙幣數(shù)目)的情況下,我們希望多貢獻點金額,這樣就可以讓紙幣數(shù)更少。這就是一種貪心算法的解決思路。
三:區(qū)間覆蓋
假設(shè)有n個區(qū)間,區(qū)間的起始端點和結(jié)束端點分分別是[l1,r1],[l2,r2],[l3,r3]……,從n個區(qū)間中選出一部分區(qū)間,這部分區(qū)間滿足兩兩不相交(端點相交的情況不算相交),最多能選出多少個區(qū)間?
我們假設(shè)這 n 個區(qū)間中最左端點是 lmin,最右端點是 rmax。這個問題就相當于,我們選擇幾個不相交的區(qū)間,從左到右將[lmin, rmax]覆蓋上。我們按照起始端點從小到大的順序?qū)@ n 個區(qū)間排序。
我們每次選擇的時候,左端點跟前面的已經(jīng)覆蓋的區(qū)間不重合的,右端點又盡量小的,這樣可以讓剩下的未覆蓋區(qū)間盡可能的大,就可以放置更多的區(qū)間。這實際上就是一種貪心的選擇方法。
四:如何用貪心算法實現(xiàn)霍夫曼編碼?
假設(shè)有一個包含1000個字符的文件,每個字符占1個byte(1byte=8bits),存儲這1000個字符就一共需要8000bits。
但使用霍夫曼編碼,可實現(xiàn)壓縮率在20%~90%之間。
霍夫曼編碼不僅會考察文本匯總有多少個不同字符,還會考察每個字符出現(xiàn)的頻率,根據(jù)頻率的不同,選擇不同長度的編碼。霍夫曼編碼試圖用這種不等長的編碼方法,來進一步增加壓縮的效率。
根據(jù)貪心的思想,可以把出現(xiàn)頻率比較多的字符,用稍微短一些的編碼;出現(xiàn)頻率比較少的字符,用稍微長一些的編碼。
由于霍夫曼編碼是不等長的,每次應(yīng)該讀取1為還是2位,3位等來解壓縮是個問題,這個問題導(dǎo)致霍夫曼編碼解壓縮比較復(fù)雜。
為了避免解壓縮過程中的歧義,霍夫曼編碼要求各個字符的編碼之間,不會出現(xiàn)某個編碼是另一個編碼前綴的情況。
假設(shè)這6個字符出現(xiàn)的頻率從高到低依次是a,b,c,d,e,f。我們把它們編碼下面這個樣子,任何一個字符的編碼都不是另一個的前綴,在解壓縮的時候,我們每次會讀取盡可能長的可解壓縮的二進制,所以在解壓縮的時候也不歧義。
根據(jù)字符出現(xiàn)頻率的不同,給不同的字符進行不同長度的編碼的實現(xiàn)方式
把每個字符看作一個節(jié)點,并且輔帶著把頻率放到優(yōu)先級隊列中。從隊列中取出頻率最小的兩個節(jié)點A,B,然后新建一個節(jié)點C,把頻率設(shè)置為兩個節(jié)點的頻率之和,并把這個新節(jié)點C作為節(jié)點A,B的父節(jié)點。最后再把C節(jié)點放入到優(yōu)先級隊列中。重復(fù)這個過程,直到隊列中沒有數(shù)據(jù)。
給每一條邊畫上一個權(quán)值,指向左子節(jié)點的邊,我們統(tǒng)統(tǒng)標記為0,指向右子節(jié)點的邊,我們統(tǒng)統(tǒng)標記為1,那從根節(jié)點到葉節(jié)點的路徑就是葉節(jié)點對應(yīng)字符的霍夫曼編碼
筆記整理來源: 王爭 數(shù)據(jù)結(jié)構(gòu)與算法之美
總結(jié)
以上是生活随笔為你收集整理的【数据结构与算法】【算法思想】贪心算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7.java.lang.IllegalA
- 下一篇: 修改 jquery.validate.j