[算法01]遞歸算法的時間複雜度終結篇

本文章轉載自http://www.cnblogs.com/python27/archive/2011/12/09/2282486.html 


 開篇前言:爲什麼寫這篇文章?筆者目前在學習各種各樣的算法,在這個過程中,頻繁地碰到到遞歸思想和分治思想,驚訝於這兩種的思想的偉大與奇妙的同時,經常要面對的一個問題就是,對於一個給定的遞歸算法或者用分治思想縮小問題規模的算法,如何求解這個算法的時間複雜度呢?在google過很多的博文後,感覺這些博文總結的方法,有很好優秀的地方,但是都不夠全面,有感於此,筆者決定總結各家之長,作此博文,總結各種方法於此,有不足之處,歡迎各位批評指證!

  在算法的分析中,當一個算法中包含遞歸調用時,其時間複雜度的分析會轉化成爲一個遞歸方程的求解。而對遞歸方程的求解,方法多種多樣,不一而足。本文主要介紹目前主流的方法:代入法,迭代法,公式法,母函數法,差分方程法。


   【代入法】代入法首先要對這個問題的時間複雜度做出預測,然後將預測帶入原來的遞歸方程,如果沒有出現矛盾,則是可能的解,最後用數學歸納法證明。

  【舉   例】我們有如下的遞歸問題:T(n)=4T(n/2)+O(n),我們首先預測時間複雜度爲O(n2),不妨設T(n)=kn2(其中k爲常數),將該結果帶入方程中可得:左=kn2,右=4k(n/2)2+O(n)=kn2+O(n),由於n2的階高於n的階,因而左右兩邊是相等的,接下來用數學歸納法進行驗證即可。


   【迭代法】迭代法就是迭代的展開方程的右邊,直到沒有可以迭代的項爲止,這時通過對右邊的和進行估算來估計方程的解。比較適用於分治問題的求解,爲方便討論起見,給出其遞歸方程的一般形式:

  【舉   例】下面我們以一個簡單的例子來說明:T(n)=2T(n/2)+n2,迭代過程如下:

  容易知道,直到n/2^(i+1)=1時,遞歸過程結束,這時我們計算如下:

  到這裏我們知道該算法的時間複雜度爲O(n2),上面的計算中,我們可以直接使用無窮等比數列的公式,不用考慮項數i的約束,實際上這兩種方法計算的結果是完全等價的,有興趣的同學可以自行驗證。


  【公式法】這個方法針對形如:T(n) = aT(n/b) + f(n)的遞歸方程。這種遞歸方程是分治法的時間複雜性所滿足的遞歸關係,即一個規模爲n的問題被分成規模均爲n/b的a個子問題,遞歸地求解這a個子問題,然後通過對這a個子問題的解的綜合,得到原問題的解。這種方法是對於分治問題最好的解法,我們先給出如下的公式:

  公式記憶:我們實際上是比較n^logba和f(n)的階,如果他們不等,那麼T(n)取他們中的較大者,如果他們的階相等,那麼我們就將他們的任意一個乘以logn就可以了。按照這個公式,我們可以計算【迭代法】中提到的例子:O(f(n))=O(n2),容易計算另外一個的階是O(n),他們不等,所以取較大的階O(n2)。太簡單了,不是嗎?

  需要注意:上面的公式並不包含所有的情況,比如第一種和第二種情況之間並不包含下面這種情況:f(n)是小於前者,但是並不是多項式的小於前者。同樣後兩種的情況也並不包含所有的情況。爲了好理解與運用的情況下,筆者將公式表述成如上的情況,但是並不是很嚴謹,關於該公式的嚴密討論,請看這裏。但是公式的不包含的情況,我們很少很少碰到,上面的公式適用範圍很廣泛的。

  特別地,對於我們經常碰到的,當f(n)=0時,我們有:


  【母函數法】母函數是用於對應於一個無窮序列的冪級數。這裏我們解決的遞歸問題是形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n)。爲說明問題簡便起見,我們選擇斐波那契數列的時間複雜度作爲例子進行討論。

  【舉  例】斐波那契數列遞歸公式:T(n)=T(n-1)+T(n-2)。這裏我們假設F(n)爲第n項的運算量。則容易得到:F(n)=F(n-1)+F(n-2),其中F(1)=F(2)=1.我們構造如下的母函數:G(x)=F(1)x+F(2)x2+F(3)x3+......,我們可以推導如下:

  上面的方法計算相對來說是比較簡單的,關鍵在於對於母函數的理解,剛開始的時候可能不是很好理解,對於母函數可以參考這裏維基百科這裏


  【差分方程法】可以將某些遞歸方程看成差分方程,通過解差分方程的方法來解遞歸方程,然後對解作出漸近階估計。這裏我們只考慮最長常見的遞歸形式,形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n),其中c1,c2,...ck爲常數且不等於0;我們對該方程的求解如下:

  對應上面的齊次方程的特徵方程爲:

  如果解得t=r是該特徵方程的m重根,則這m個解的形式爲:{rn     n*rn      n2rn   ...    nm-1rn},其餘的關於複數解的形式和普通的線性方程組的形式類似,不再贅述。接下來,我們要求解該方程的對應非齊次方程組的通解,這裏我們針對該方程的特殊形式,不加證明地給出如下的通解形式:

  則和線性代數中的解一樣,原方程的解等於齊次方程組的通解+特解,即:

  最後由初始條件確定a(i)的值即可。

  爲了幫助理解,我們舉兩個例子看看,就明白是怎麼回事了。

  【舉 例1】遞歸方程如下:

(1)寫出對應齊次方程的特徵方程:

得到基礎解係爲:{t1n,  t2n}

(2)計算特解,對於本題,直接觀察得特解爲:-8

(3)得到原方程解的形式爲:T(n)=a0t1n+a1t2n-8

(4)代入n=0,n=1的情況,得到a0,a1,最後可得:

  可以看到該方程形式和上面討論過的斐波那契數列只差一個常數8,因而兩者的時間複雜度是相同的。有興趣的同學可以按照這個方法再次計算斐波那契數列的時間複雜度驗證一下。

  【舉  例2】遞歸方程如下:

(1)計算對應齊次方程的基礎解析:

特徵方程爲:C(t)=t^2-4t-4=0,得到一個2重根t=2.因而其基礎解爲:{2n      n*2n}

(2)由於f(n)=n*2n,對應上面表格的最後一種情況,得到特解形式爲:T(n)=n2(p0+p1n)2n代入原遞歸方程可得:p0=1/2,p1=1/6

(3)原方程解的形式爲:T(n)=a0*2n+a1*n*2n+n2(1/2+n/6)2n,代入T(0),T(1)得:a0=a1=0

(4)綜上:T(n)=n2(1/2+n/6)2n

因而時間複雜度爲:O(n32n)


 

References:

[1]青青的專欄:http://blog.csdn.net/metasearch/article/details/4428865

[2]心靈深處博客:http://blog.csdn.net/metasearch/article/details/4428865

[3]wikipedia中文:母函數

[4]母函數的性質和應用:http://www.doc88.com/p-39037791334.html

[5]關於遞歸算法時間複雜度分析的討論:http://wenku.baidu.com/view/719b053331126edb6f1a1091.html

[6][置頂]遞歸方程組解的漸進階的求法——差分方程法:http://blog.csdn.net/explore_knight/article/details/1788046

注:

1)本博客所有的代碼環境編譯均爲win7+VC6。所有代碼均經過博主上機調試。

2)博主python27對本博客文章享有版權,網絡轉載請註明出處http://www.cnblogs.com/python27/。對解題思路有任何建議,歡迎在評論中告知。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章