TS數(shù)據(jù)結(jié)構(gòu)與算法之求斐波那契數(shù)列的第n值

需求

  • 用JS計算斐波那契數(shù)列的第n個值
  • 注意時間復(fù)雜度
  • 0 1 1 2 3 5 8 13 21 34...

公式

  • f(0) = 0
  • f(1) = 1
  • f(n) = f(n-1) + f(n-2)

功能實現(xiàn)-遞歸方式

/**
 * @description 斐波那契數(shù)列 - 遞歸方式實現(xiàn)
 */
export const fibonacci = (n: number): number => {
  if (n <= 0) return 0;
  if (n === 1) return 1;

  return fibonacci(n - 1) + fibonacci(n - 2);
}

遞歸分析

  • 大量的重復(fù)計算
  • 時間復(fù)雜度是 O(2^n)
  • 遞歸方式完全不可用

優(yōu)化

  • 不用遞歸芬骄,用循環(huán)
  • 記錄中間結(jié)果
  • 時間復(fù)雜度為 O(n)

功能實現(xiàn) - 循環(huán)方式

 0   1  1    2   3   5   8   13   21   34
 |   |  |
 n2  n1 res

每次循環(huán) n1 n2 整體后移

/**
 * @description 斐波那契數(shù)列 - 循環(huán)方式實現(xiàn)
 */
export const fibonacciLoop = (n: number): number => {
  if (n <= 0) return 0;
  if (n === 1) return 1;

  let n1 = 1; // 記錄 n - 1 的結(jié)果
  let n2 = 0; // 記錄 n - 2 的結(jié)果
  let res = 0;

  for (let i = 2; i <= n; i++) {
    res = n1 + n2;

    // 記錄中間結(jié)果
    n2 = n1;
    n1 = res;
  }

  return res;
}

功能測試

export const fibonacciFunctionalTest = () => {
  console.log(fibonacciLoop(0)); // 0
  console.log(fibonacciLoop(3)); // 2
  console.log(fibonacciLoop(6)); // 8
  console.log(fibonacciLoop(9)); // 34
}

單元測試

/**
 * @description 斐波那契數(shù)列單元測試
 */
import { fibonacciLoop } from '../src/utils/fibonacci';

describe('斐波那切數(shù)列', () => {
  test('0 和 1', () => {
    expect(fibonacciLoop(0)).toBe(0);
    expect(fibonacciLoop(1)).toBe(1);
  });

  test('正常情況', () => {
    expect(fibonacciLoop(2)).toBe(1);
    expect(fibonacciLoop(3)).toBe(2);
    expect(fibonacciLoop(6)).toBe(8);
  });

  test('n 小于 0', () => {
    expect(fibonacciLoop(-1)).toBe(0);
  });
});

運行 yarn jest:

 PASS  tests/fibonacci.test.ts
  斐波那切數(shù)列
    √ 0 和 1 (2 ms)
    √ 正常情況 (1 ms)
    √ n 小于 0

動態(tài)規(guī)劃

  • 把一個大問題管毙,拆解為多個小問題,逐級向下拆解
  • 用遞歸的思路分析問題寸谜,再改為循環(huán)來實現(xiàn)
  • 算法三大思維:貪心鲸阻、二分六荒、動態(tài)規(guī)劃

動態(tài)規(guī)劃(dynamic programming养距,DP)是運籌學(xué)的一個分支尤筐,是求解決策過程最優(yōu)化的數(shù)學(xué)方法汇荐。動態(tài)規(guī)劃是對某類問題的解決方法,重點在于如何鑒定一類問題是動態(tài)規(guī)劃可解的而不是糾結(jié)用什么解決方法盆繁。動態(tài)規(guī)劃中狀態(tài)是非常重要的掀淘,它是計算的關(guān)鍵,通過狀態(tài)的轉(zhuǎn)移來實現(xiàn)問題的求解改基。當(dāng)嘗試使用動態(tài)規(guī)劃解決問題時繁疤,其實就是要思考如何將這個問題表達成狀態(tài)以及如何在狀態(tài)間轉(zhuǎn)移。動態(tài)規(guī)劃總是假設(shè)當(dāng)前已取得最好結(jié)果秕狰,再依據(jù)此結(jié)果去推導(dǎo)下一步行動稠腊。遞歸法將大問題分解為小問題,調(diào)用自身鸣哀。而動態(tài)規(guī)劃從小問題推導(dǎo)到大問題架忌,推導(dǎo)過程的中間值要緩存起來,這個推導(dǎo)過程稱為狀態(tài)轉(zhuǎn)移我衬。

動態(tài)規(guī)劃代碼是迭代叹放,比遞歸代碼簡潔不少饰恕,不像遞歸版本算法,它減少了棧的使用井仰。但要意識到埋嵌,能為一個問題寫遞歸解決方案并不意味著它就是最好的的解決方案。

遞歸費棧俱恶,容易爆內(nèi)存雹嗦。動態(tài)規(guī)劃則不好找準(zhǔn)轉(zhuǎn)移規(guī)則和起始條件,而這兩點又是必須的合是,所以動態(tài)規(guī)劃好用了罪,不好理解,代碼很簡單聪全,理解很費勁兒泊藕。同樣的問題,有時遞歸和動態(tài)規(guī)劃都能解決难礼,比如斐波那契數(shù)列問題娃圆,用兩者都能解決。

注意鹤竭,能用遞歸解決的踊餐,用動態(tài)規(guī)劃不一定都能解決。因為這兩者本身就是不同的方法臀稚,動態(tài)規(guī)劃需要滿足的條件吝岭,遞歸時不一定能滿足。這一點一定牢記吧寺,不要為了動態(tài)規(guī)劃而動態(tài)規(guī)劃窜管。

所有遞歸算法都必須要滿足三定律,遞歸在某些情況下可以代替迭代稚机,但迭代不一定能替代遞歸幕帆。遞歸算法通常可以自然地映射到所解決的問題的表達式赖条,看起來很直觀簡潔失乾。遞歸并不總是好的方案,有時遞歸解決方案可能比迭代算法在計算上更昂貴纬乍。尾遞歸是遞歸的優(yōu)化形式碱茁,能一定程度上減少棧資源使用。動態(tài)規(guī)劃可用于解決最優(yōu)化問題仿贬,通過小問題逐步構(gòu)建大問題纽竣,而遞歸是通過分解大問題為小問題來逐步解決。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜓氨,隨后出現(xiàn)的幾起案子聋袋,更是在濱河造成了極大的恐慌,老刑警劉巖穴吹,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幽勒,死亡現(xiàn)場離奇詭異,居然都是意外死亡港令,警方通過查閱死者的電腦和手機代嗤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缠借,“玉大人,你說我怎么就攤上這事宜猜∑梅担” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵姨拥,是天一觀的道長绅喉。 經(jīng)常有香客問我,道長叫乌,這世上最難降的妖魔是什么柴罐? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮憨奸,結(jié)果婚禮上革屠,老公的妹妹穿的比我還像新娘。我一直安慰自己排宰,他們只是感情好似芝,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著板甘,像睡著了一般党瓮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盐类,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天寞奸,我揣著相機與錄音,去河邊找鬼在跳。 笑死枪萄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的硬毕。 我是一名探鬼主播呻引,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吐咳!你這毒婦竟也來了逻悠?” 一聲冷哼從身側(cè)響起元践,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎童谒,沒想到半個月后单旁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡饥伊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年象浑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琅豆。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡愉豺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出茫因,到底是詐尸還是另有隱情蚪拦,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布冻押,位于F島的核電站驰贷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏洛巢。R本人自食惡果不足惜括袒,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望稿茉。 院中可真熱鬧锹锰,春花似錦、人聲如沸漓库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽米苹。三九已至糕伐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蘸嘶,已是汗流浹背良瞧。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留训唱,地道東北人褥蚯。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像况增,于是被迫代替她去往敵國和親赞庶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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