初窺門徑 - 原來遞歸斐波那契如此慢

初入算法的人都會聽過斐波那契數(shù)列厘托,看看維基百科的定義:

斐波那契數(shù)列(意大利語 Successione di Fibonacci)稿湿,又譯為費波拿契數(shù)斐波那契數(shù)列饺藤、費氏數(shù)列黃金分割數(shù)列罗丰。
在數(shù)學上再姑,費波那契數(shù)列是以遞歸的方法來定義:

用文字來說,就是費波那契數(shù)列由0和1開始谜嫉,之后的費波那契系數(shù)就是由之前的兩數(shù)相加而得出凹联。首幾個費波那契系數(shù)是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……

如果以編程方式來獲取第 N 個數(shù)的值沐兰,我很自然的就想到遞歸

// in javascript
function fibonacci(n){
    if(n <= 0) return 0;
    if(n == 1) return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}

看著是不是很簡潔蔽挠? 嗯瓜浸,很標準比原,邊界確定了,也有一步步遞進的求解過程雇寇,那我們放在瀏覽器 console 上跑一跑蚌铜,順便看看運行時間,為此再來幫助函數(shù)

function time(fn, ...args) {
    var start = new Date().valueOf();
    console.log(fn(...args))
    var end = new Date().valueOf();
    console.log('elapsed: ' + (end - start) + 'ms');
}

先來獲取 n = 10 的值冬殃,看下面的結果正常,1毫秒一開始也怎么在意深滚。


那再來試試 n = 50的... 等了好一會 還沒打印出來結果 還以為瀏覽器卡了;辆酢!官册!


這才到50攀隔, 就花去了330秒栖榨,5分多鐘了喂,真可怕 !?(?_?;? 連三位數(shù)都還沒到婴栽,更別說w級別以上了。

為毛會這么慢映皆?轰枝?? 我們以 n = 10 來分析下過程


先原諒我這丑不拉幾的字跡... 沿著這個樹形結構往回推進鞍陨,發(fā)現(xiàn)Fib(8) 執(zhí)行了2次,F(xiàn)ib(7)執(zhí)行了3次缭裆,F(xiàn)ib(6)執(zhí)行3次以上,存在著大量重復的計算澈驼,復雜度達到指數(shù)級別缝其,而且數(shù)量級越大重復越嚴重。這二叉樹沒有滿氏淑,我們按滿的算那總的計算次數(shù)為 T(N) = 1 + 2 + 4 + 8 + ... + 2^10 => 2^n+1 -1 大概時間復雜度是 O( (2^N), 最牛逼的那個N次方。

換個思路

前面的遞歸是從第n位往回推導的缭贡,那我們正向的去一步步得出相應位置的值辉懒,就可以省去反向遞歸帶來的大量重復操作了,也就是常說的遞推眶俩,時間復雜度為 O(N) 代碼如下:

// 遞推
function fibonacci(n) {
    if (n <= 0) return 0;
    if (n == 1) return 1;

    var first = 0,
        second = 1,
        index = 1,
        fib = 0;

    while (index++ < n) {
        fib = first + second;
        first = second;
        second = fib;
    }
    return fib;
}

試驗下, 50 幾乎不耗時


慢慢往上加颠印, 可以看到到1w的時候 js的數(shù)字已經(jīng)裝不下了, 但是獲取第10w位置的也才需要2ms的時間线罕。


補充@林曉池Smile 評論的說法钞楼, 以空間換時間,利用數(shù)組來存儲已經(jīng)計算過的斐波那契數(shù)列中的值

var memo = [];
function fibonacci(n){
    if(n <= 0) return 0;
    if(n == 1) return 1;
    if(!memo[n])
        memo[n] = fibonacci(n-1) + fibonacci(n-2);
    return memo[n];
}

測試看看



可以看到相比一開始的遞歸询件,省去了很多重復的計算;但是獲取第10w個數(shù)的時候堆棧就溢出了刻蟹,因為即使記憶了但是還存在遞歸調用嘿辟, 遞推的方案倒是不會
調用堆棧的上限如下:
Three results:
Node.js: 11034
Firefox: 50994
Chrome: 10402

入門例子就可以體會到合理選擇算法的威力了痢艺,我要繼續(xù)努力~ 為分布式系統(tǒng)節(jié)省機器

網(wǎng)上對斐波那契有其他更優(yōu)質的算法介陶,但是那種數(shù)學公司俺看不懂。舌缤。某残。 以后再回爐重造學習高數(shù)吧国撵。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末介牙,一起剝皮案震驚了整個濱河市澳厢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剩拢,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贯钩,死亡現(xiàn)場離奇詭異办素,居然都是意外死亡,警方通過查閱死者的電腦和手機勺三,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門季二,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揭措,“玉大人,你說我怎么就攤上這事绊含。” “怎么了逃顶?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霸褒。 經(jīng)常有香客問我盈蛮,道長,這世上最難降的妖魔是什么抖誉? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮旁理,結果婚禮上我磁,老公的妹妹穿的比我還像新娘。我一直安慰自己十性,他們只是感情好,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布楷掉。 她就那樣靜靜地躺著霞势,像睡著了一般。 火紅的嫁衣襯著肌膚如雪草雕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天墩虹,我揣著相機與錄音憨琳,去河邊找鬼。 笑死菌湃,一個胖子當著我的面吹牛遍略,可吹牛的內(nèi)容都是我干的骤坐。 我是一名探鬼主播下愈,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驰唬!你這毒婦竟也來了?” 一聲冷哼從身側響起辖佣,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤搓逾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后霞篡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡污淋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年寸爆,在試婚紗的時候發(fā)現(xiàn)自己被綠了盐欺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡冗美,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出节预,到底是詐尸還是另有隱情属韧,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布去扣,位于F島的核電站柱衔,受9級特大地震影響愉棱,放射性物質發(fā)生泄漏哲戚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一朋其、第九天 我趴在偏房一處隱蔽的房頂上張望脆炎。 院中可真熱鬧,春花似錦秒裕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弧烤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扼褪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工脏毯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幔崖,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓吉嫩,卻偏偏與公主長得像嗅定,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子渠退,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容