遞歸的時間復雜度你真的懂嗎?不是所有的二分遞歸都是logn級別


本篇文章的書寫靈感來源於【代碼隨想錄】,自己寫東西純粹只是給自己看,而且我寫的東西估計只有我自己才能看懂,laugh@Hygge。

首先說明一下,在我很長一段時間這樣以為,二分遞歸這一部分的時間復雜度肯定是O(log n),但是我實在太天真了 :(

以下通過舉例說明說明情況:計算xn的簡單題

最容易想到的O(n)算法代碼直接略過,將x一個一個依次乘起來,這種方法在面試官看來,簡直就是violence。 

接下里我們想想還有其他方法嗎?比如,萬能的縮小時間復雜度的遞歸,這樣會有如下的思路

想到:利用二分進行遞歸?哇塞,感覺發現了新大陸,please No talking,show me UR code!

1     function (int x, int n){
2         if (n == 0):
3             return 1
4         if (n % 2 == 1): # 判奇偶性
5             return function(x, n / 2) * function(x, n / 2) & x
6         else:
7             return function(x, n / 2) * function(x, n / 2)
8     }

寫出這樣的代碼,哇塞,天之驕子啊!但是你確定這樣的遞歸縮短了時間復雜度到O(logn)嗎?

我么來分析一波!!!

在這里,很容易犯的誤區來了,你看這個遞歸樹的深度就是logn,所以說時間復雜度就是logn(感覺理直氣壯)!但是首先我來說明第一個誤區:遞歸樹的深度不是時間復雜度,時間復雜度計算公式應該是「遞歸的次數 * 每次遞歸中的操作次數」,在上圖中,仔細想一想,每一個node會執行一次乘法,但是然后自頂向上,計算乘法的次數是23(第4層遞歸操作次數)+22(第3層遞歸操作次數)+21(第2層遞歸操作次數)+2(第1層遞歸操作次數)= 24 - 1(順便記住計算n層滿二叉樹的公式,以后面試可能會遇到)。最后:我們發現上面代碼執行的遞歸時間復雜度還是O(n)!所以這個遞歸和violence的時間復雜度還是一樣,而且遞歸反而還要增加一個系統自動維護地遞歸棧,切線程,非常耗時!

在這里,我們根據算法中主定理(T(n) = aT(n /b) + nd)來解釋時間復雜度:T(n)= 2T(n/2) + 1(這個加的1是合起來的一次乘法運算),根據主定理,a=2,b=2,d=0,a<bd,所以T(n) = nlogba=nlog22=n,綜上所述,T(n) = n (That's way bad!)

言歸正傳,那么遞歸根本沒有進行改進呀呀呀,有其他方法改改進嗎?哈哈哈哈哈,答案是肯定的,霍納法則!霍納法則就是專門解決xn的計算問題滴!

霍納法則的代碼和矩陣快速冪一樣,模板如下:

1     ans = 1
2     function (int x, int n){
3         while n:
4             if n & 1:
5                 ans = y * x
6             x = x * x
7             n = n > 1 #n/2
8     }

 

這個辦法沒有用到遞歸,但是時間復雜度分析真正實現了O(logn),congrats{✿✿ヽ(°▽°)ノ✿}!!!

好了,寫完了,總結一下:

1.使用遞歸,時間復雜度絕對不總是O(logn)

2.霍納法則求n次方問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM