算法之遞歸、分治策略、動態規劃以及貪心算法之間的關係

https://blog.csdn.net/tyhj_sf/article/details/53969072算法

轉載:http://blog.csdn.net/tyhj_sf/article/details/53969072markdown

引言

最近集中研究計算智能,其中涉及到遞歸和動態規劃,動態規劃實現中又用到了遞歸,突然發現這兩個概念的差異分得不太清楚。索性把遞歸、分治策略、動態規劃、貪婪選擇之間的聯繫與區別都一併搞清楚吧。ide

一、分治策略(Divide and Conquer)

將原問題分解爲若干個規模較小但相似於原問題的子問題(Divide),遞歸的求解這些子問題(Conquer),而後再合併這些子問題的解來創建原問題的解。由於在求解大問題時,須要遞歸的求小問題,所以通常用遞歸的方法實現,即自頂向下。post

二、動態規劃(Dynamic Programming)

動態規劃其實和分治策略是相似的,也是將一個原問題分解爲若干個規模較小的子問題,遞歸的求解這些子問題,而後合併子問題的解獲得原問題的解。區別在於這些子問題會有重疊,一個子問題在求解後,可能會再次求解,因而咱們想到將這些子問題的解存儲起來,當下次再次求解這個子問題時,直接拿過來就是。其實就是說,動態規劃所解決的問題是分治策略所解決問題的一個子集,只是這個子集更適合用動態規劃來解決從而獲得更小的運行時間。即用動態規劃能解決的問題分治策略確定能解決,只是運行時間長了。所以,分治策略通常用來解決子問題相互對立的問題,稱爲標準分治,而動態規劃用來解決子問題重疊的問題。性能

動態規劃通常由兩種方法來實現,一種爲自頂向下的備忘錄方式,用遞歸實現,一種爲自底向上的方式,用迭代實現。ui

三、貪心算法(Greedy Algorithm)

貪心算法在每一步都作出最優的選擇,但願這樣的選擇能致使全局最優解。對,只是寄但願,所以貪心算法並不保證獲得最優解,可是它對不少問題確實能夠獲得最優解,並且運行時間更短。因而可知,貪心算法是帶有啓發性質的算法。那何時能夠用貪心算法呢?當該問題具備貪心選擇性質的時候,咱們就能夠用貪心算法來解決該問題。 
貪心選擇性質:咱們能夠經過作出局部最優(貪心)來構造全局最優。只要咱們可以證實該問題具備貪心選擇性質,就能夠用貪心算法對其求解。好比對於0-1揹包問題,咱們用貪心算法可能得不到最優解(固然,也可能會獲得最優解),但對於部分揹包問題,則能夠獲得最優解,貪心算法能夠做爲0-1揹包問題的一個近似算法。spa

動態規劃與遞歸的比較

就性能而言,我用遞歸和動態規劃實現了斐波納契數列計算,遞歸若是超過40的時候就已經須要很長時間了,40次大概須要1秒左右,可是用動態規劃要一億次,才須要4秒,這個相差的可不是幾個數量級的問題。事實上,遞歸實現的斐波那契數列計算時間複雜度爲O(2ⁿ),動態規劃實現時間複雜度爲O(n)因此,在之後的開發中,儘可能避免使用遞歸。 
就具體實現上而言,動態規劃比普通遞歸僅僅是多了一步保存子問題計算結果的操做。 
例如,斐波那契數列的遞歸實現以下:.net

int F(int i) { if(i < 1) return 0; if(i == 1) return 1; return F(i-1) + F(i - 2); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

而用動態規劃算法實現是這樣:code

int F(int i) { if(knownF[i] != unknown){ return knownF[i]; } if(i == 0) t = 0; if(i == 1) t = 1; if(i > 1) t = F(i - 1) + F(i - 2); return knownF[i] = t; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、總結

  1. 分治策略用於解決原問題與子問題結構類似的問題,對於各子問題相互獨立的狀況,通常用遞歸實現;
  2. 動態規劃用於解決子問題有重複求解的狀況,既能夠用遞歸實現,也能夠用迭代實現;
  3. 貪心算法用於解決具備貪心選擇性質的一類問題,既能夠用遞歸實現,也能夠用迭代實現,由於不少遞歸貪心算法都是尾遞歸,很容易改爲迭代貪心算法;
  4. 遞歸是實現手段,分治策略是解決問題的思想,動態規劃不少時候會使用記錄子問題運算結果的遞歸實現。

參考資料: 
1.http://1661518.blog.51cto.com/1651518/1396943 
2.《算法導論》第三版blog

相關文章
相關標籤/搜索