JS 從斐波那契數列淺談遞歸


一、前言

昨晚下班后,經理出於興趣給我們技術組講了講算法相關的東西,全程一臉懵逼的聽,中途還給我們出了一道比較有趣的爬樓問題,問題如下:

假設一個人從地面開始爬樓梯,規定一步只能爬一坎或者兩坎,人只能往上走,例如爬到第一坎,很明顯從地面到第一坎只有一種可選方式,從地面爬到第二坎,他可以從地面直接跨到第二坎,也可以先從地面到第一坎,再從第一坎到第二坎,也就是2種可選方式,那么求他爬到N樓一共有幾種可選方式。

這道題涉及到了斐波那契數列,要求使用遞歸來求值,技術賊菜的我也是一臉懵逼,所以本着學習的心還是記錄下來了。

二、有趣的斐波那契數列

我們將地面理解為數字0,第一坎理解為數字1,以此來進行簡單的分析:

例如從0到1,就一種選擇,如圖(公司不讓用破解軟件,沒PS畫圖,湊合看吧,畫圖的手微微顫抖。。。)

那么,現在要求到第二坎,從0到2呢,兩種選擇,看圖分析(記住,一步只能跨一坎或者兩坎):

當要求從0到3,三種選擇,如圖:

紫色:一坎坎的走;黃色:先走兩坎,再走一坎;藍色:先走一坎,再走兩坎。

從0-4,一共五種情況,如圖:

這里我分開畫了,左邊的2種情況加上右邊的三種情況

左邊:

第一種:一坎坎的走,0-1-2-3-4

第二種:兩坎兩坎走,0-2-4

右邊:

第三種:先走兩坎,再一坎坎的走0-2-3-4

第四種:先走一坎,再走兩坎,再走一坎0-1-3-4

第五種:先走一坎,再走一坎,再走兩坎0-1-2-4

當我們繼續往后畫,樓梯層對應走法會形成一個有趣的規律,

從第三層開始,第三層的走法等於一層與二層走法的和,第四層的走法等於第二層和第三層走法的和.....針對樓梯問題,我們可以得到如下公式:

F(n) = F(n-1) + F(n-2)   n>=3

這就是著名的斐波那契數列(Fibonacci sequence),又稱黃金分割數列。有興趣的同學可以查查兔子繁殖問題。

百科里斐波那契數列的基數n>=4是根據實際情況來定的,這點不用糾結。

三、斐波那契數列與遞歸的結合

什么是遞歸?自己調用自己的函數就是遞歸,這么說完全沒問題。

我們回歸上面的問題,要求第N層的走法,那我們只需要知道N-1層和N-2層的走法就好了,假設N是10,求到第十層的走法。

十層走法=九層的走法+八層走法

九層和八層也可以拆分啊,九層走法 = 七層走法 + 八層走法 ,而八層走法 = 七層走法 + 六層走法

.......

當分到3層時,最后還可以拆分為1層+2層,因為規律是從第三層開始的,因為此公式不適用於1層和2層,分到1層和2層就代表分支的結束了。

使用閉包需要找到跳出自己調用自己的的臨界條件,不然會會陷入死循環,那對應我們的樓梯問題,只要N<3時就不需要繼續調用自己了,因為不需要繼續產生分支了。

這個閉包怎么寫呢?我們結合斐波那契數列公式嘗試一下吧。

現在有一個函數,里面申明一個走法變量var step = 0;輸入一個數字N,我們會對N判斷,只要N>=3,它就會自己調用自己,小於3時,我們分別判斷它等於1或者2,等於1就讓step加1,等於2就讓step加2,如下:

function recursion(n){
    let step = 0;
    if (n === 1 ){
        step += 1
    }else if (n === 2){
        step += 2;
    }else if (n >= 3){
        step = recursion(n-1) + recursion(n-2);
    };
    return step;
};
console.log(recursion(10))//89種

為了驗證,我將上方分支圖中所有的1與2相加(1層只有1種走法,2層有2種),得出數字也確實是89。所以我不明白我為什么要把基數N設置為10,算的難受。

那么趁熱打鐵,活學活用,現在我們嘗試求正整數N與N之前所有正整數累加的和

例如3之前累加的和就是3+2+1,數字0加不加沒意義,所以跳出遞歸的臨界條件就是當N>=2時,最后調用一次讓之前數字的和加一次1就好了。

var result = 0;
function add(n){
    result += n
    n>=2 ? add(n-1) : null;
    return result;
};
console.log(add(10));//55

驗證一下,完全沒問題,有沒有覺得遞歸挺簡單。

當你看到這時,恭喜你,不僅了解了斐波那契數列,也簡單了解了遞歸的用法。其實本人在工作中需要操作數據,本能的總是想到窮舉,循環,那么現在又多了一種可行的解決方法,也算是對於思維的開拓了。

留個問題,回到上方兩段實現代碼,為什么第一個變量申明在函數體內,而第二個數字累加的變量申明要在函數體外呢?嘗試思考下。

當然,前提是,這篇博客如果有人願意看完就挺好了。


免責聲明!

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



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