斐波那契數(shù)列的一些思考與延伸

先看代碼:

function fib(n){
    if(n===1){
        return 1;
    }
    if(n===2){
        return 1;
    }
    if(n>2){
        return fib(n-1)+fib(n-2);
    }
}
console.log(fib(11));

這是一個很典型的利用遞歸計算斐波那契數(shù)列。

遞歸的缺點也是顯而易見的,我們計算fib(6)時 要計算fib(5)和fib(4)

而后計算fib(7)時,又要重復(fù)計算fib(6)與fib(5)

很明顯,我們之前已經(jīng)計算過了fib(6)與fib(5),現(xiàn)在重復(fù)計算,造成了浪費.

首先我們來觀察一下 當(dāng)n從20到21時,調(diào)用此函數(shù) 內(nèi)部會多調(diào)用多少次此函數(shù)?

var count=0;//計數(shù)器
function fib(n){
    count++;
    if(n===1){
        return 1;
    }
    if(n===2){
        return 1;
    }
    if(n>2){
        return fib(n-1)+fib(n-2);
    }
}
console.log(fib(20));
console.log(count);//13529次
count = 0;
console.log(fib(21));
console.log(count);//21891次  從20到21 調(diào)用次數(shù)增加不少

其實我們完全可以將之前計算過的數(shù)值用一個數(shù)組保存起來心例,如果需要重復(fù)計算闷旧,先去數(shù)組內(nèi)部查找,如果數(shù)組里面存在該結(jié)果,直接return

var cache = [0,1,1];
function fib(n){
    if(n<=2){
        return cache[n];
    }else{
        if(cache[n]){ //如果緩存數(shù)組中存在 直接返回
            return cache[n];
        }else{
            var temp = fib(n-1)+fib(n-2); //如果緩存數(shù)組中不存在 進行遞歸
            cache[n]=temp;   //將遞歸結(jié)果存入緩存數(shù)組
            return temp;
        }
    }
 }

這樣已經(jīng)能夠節(jié)省很多遞歸造成的空間浪費了。

但是緩存數(shù)組孤零零的放在全局作用域,不夠安全旨指,封裝性也不好,比較寂寞喳整。

我們希望他們聯(lián)系的能夠更緊密一些谆构,就像一個整體。

于是有了下面的代碼:

var fib = (function(){
    var cache = [0,1,1];
    var fib = function() {
        if(n<=2){
            return cache[n];
        }else{
            if(cache[n]){ //如果緩存數(shù)組中存在 直接返回
                return cache[n];
            }else{
                var temp = fib(n-1)+fib(n-2); //如果緩存數(shù)組中不存在 進行遞歸
                cache[n]=temp;   //將遞歸結(jié)果存入緩存數(shù)組
                return temp;
            }
        }
    }
    return fib;
})()

這樣框都,我們通過閉包搬素,只能通過返回的fib方法對cache進行操作了。

當(dāng)然魏保,你也可以像下面這樣寫:

function createCache(){
    var cache=[0,1,1];//緩存數(shù)組被封裝在閉包中,外界只能通過返回的方法進行操作
    return function editCache(index,value){
        if(value==undefined){
            return cache[index];
        }else{
            cache[index]=value;
        }
    }
 }

 var fibCache=createCache();//創(chuàng)建緩存數(shù)組并且獲取接口方法

 function fib(n){
    if(n<=2){
        return fibCache(n);
    }else{
        if(fibCache(n)){
            return fibCache(n);
        }else{
            var temp = fib(n-1)+fib(n-2);
            fibCache(n,temp);
            return temp;
        }
    }
 }

遞歸效率低是函數(shù)調(diào)用的開銷導(dǎo)致的熬尺。

在一個函數(shù)調(diào)用之前需要做許多工作,比如準(zhǔn)備函數(shù)內(nèi)局部變量使用的空間谓罗、搞定函數(shù)的參數(shù)等等粱哼,這些事情每次調(diào)用函數(shù)都需要做,因此會產(chǎn)生額外開銷導(dǎo)致遞歸效率偏低 來自知乎

其實一般遞歸的方法我們都可以通過迭代的方式來做檩咱,for循環(huán)就是一個很好的選擇:

function fib(n) {
    if (n == 1 || n == 2) {
        return 1;
    }
    var arr = [0,1,1];
    for(var i = 2; i <= n; i++) {
        arr[i] = arr[i-1] + arr[i-2];
    }
    return arr[n];
}

看起來也挺好的揭措,是吧。

下面進入算法時間税手,題目來自《劍指Offer》蜂筹,當(dāng)然需纳,遞歸依然是主角芦倒。

題目一:
一只青蛙一次可以跳上 1 級臺階,也可以跳上 2 級不翩。求該青蛙跳上一個 n 級的臺階總共有多少種跳法兵扬?

解題:數(shù)學(xué)歸納法。
1級臺階口蝠,1種跳法器钟,直接跳上1級臺階 f(1) = 1;

2級臺階妙蔗,2種跳法傲霸,直接跳上2級臺階或者連續(xù)跳兩次,每次一級 f(2) = 2;

3級臺階昙啄,如果第一次跳1級穆役,剩下2級臺階,f(2) = 2種跳法;如果第一次跳2級梳凛,剩下1級臺階耿币,f(1) = 1種跳法。f(3) = f(2) + f(1) = 2 + 1 = 3韧拒;

4級臺階淹接,如果第一次跳1級,剩下3級臺階叛溢,由上一條可知有3種跳法塑悼;如果第一次跳2級,剩下2級臺階雇初,由上上條可知有2種跳法拢肆,f(4) = f(3) + f(2) = 3 + 2 = 5;

n級臺階靖诗,f(n) = f(n-1) + f(n-2)

很熟悉對嗎郭怪?

function jump(n) {
    if (n <= 0) {
        return;
    } else if (n > 0 && n <= 2) {
        return n;
    } else if (n > 2) {
        return jump(n-1) + jump(n-2);
    }
}

題目二:
一只青蛙一次可以跳上 1 級臺階,也可以跳上 2 級……它也可以跳上 n 級刊橘。求該青蛙跳上一個 n 級的臺階總共有多少種跳法鄙才?

解題:繼續(xù)歸納。
1級臺階促绵,1種跳法

2級臺階攒庵,2種跳法

3級臺階,4種跳法 f(3) = f(2) + f(1) + 1 = 4

4級臺階败晴,第一次跳1級浓冒,后面有f(3)種跳法,第一次跳2級尖坤,后面有f(2)種跳法稳懒,第一次跳3級,后面有f(1)種跳法慢味,第一次跳4級场梆,沒了
總共f(4) = f(3) + f(2) + f(1) + 1 = 8種跳法

5級臺階,f(5) = f(4) + f(3) + f(2) + f(1) + 1 = 16種跳法

歸納得纯路,f(n) = f(n-1) + f(n-2) + ... + f(1) + 1

function jump(n) {
    if (n <= 0) {
        return;
    } else if (n > 0 && n <= 2) {
        return n;
    } else if (n > 2) {
        var tmp = 0;
        while(number > 1){
            tmp+=jump(n-1);
            number--;
        }
        return tmp+1;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末或油,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驰唬,更是在濱河造成了極大的恐慌顶岸,老刑警劉巖腔彰,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異辖佣,居然都是意外死亡萍桌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門凌简,熙熙樓的掌柜王于貴愁眉苦臉地迎上來上炎,“玉大人,你說我怎么就攤上這事雏搂∨菏” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵凸郑,是天一觀的道長裳食。 經(jīng)常有香客問我,道長芙沥,這世上最難降的妖魔是什么诲祸? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮而昨,結(jié)果婚禮上救氯,老公的妹妹穿的比我還像新娘纳令。我一直安慰自己凤瘦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布换吧。 她就那樣靜靜地躺著务嫡,像睡著了一般甲抖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上心铃,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天准谚,我揣著相機與錄音,去河邊找鬼去扣。 笑死柱衔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厅篓。 我是一名探鬼主播秀存,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捶码,長吁一口氣:“原來是場噩夢啊……” “哼羽氮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惫恼,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤档押,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體令宿,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡叼耙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粒没。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筛婉。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖癞松,靈堂內(nèi)的尸體忽然破棺而出爽撒,到底是詐尸還是另有隱情,我是刑警寧澤响蓉,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布硕勿,位于F島的核電站,受9級特大地震影響枫甲,放射性物質(zhì)發(fā)生泄漏源武。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一想幻、第九天 我趴在偏房一處隱蔽的房頂上張望粱栖。 院中可真熱鬧,春花似錦脏毯、人聲如沸查排。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跋核。三九已至,卻和暖如春叛买,著一層夾襖步出監(jiān)牢的瞬間砂代,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工率挣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刻伊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓椒功,卻偏偏與公主長得像捶箱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子动漾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

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

  • 原文鏈接:http://blog.csdn.net/qq_22329521/article/details/529...
    越長越圓閱讀 1,571評論 0 1
  • 斐波那契數(shù)列(Fibonacci sequence)丁屎,又稱黃金分割數(shù)列。 解法: 1旱眯、遞歸 2晨川、累加(去重復(fù)) 3...
    Arya鑫閱讀 568評論 0 0
  • 零碎 標(biāo)識符 關(guān)鍵字 運算符號 邏輯運算符 執(zhí)行順序& if else & switch 順序執(zhí)行 分支執(zhí)行 循環(huán)...
    陳小飄閱讀 341評論 0 0
  • 題目描述 大家都知道斐波那契數(shù)列证九,現(xiàn)在要求輸入一個整數(shù)n,請你輸出斐波那契數(shù)列的第n項共虑。n<=39 常見的遞歸做法...
    clshinem閱讀 198評論 1 1
  • 我辟谷初心是想排腸毒減腰圍愧怜,辟前體重51公斤。半個月前妈拌,我和老公說我想辟谷拥坛。他立馬長篇大論專家式的發(fā)表一通...
    謝謝環(huán)閱讀 1,168評論 0 2