演算法練習01 記憶化斐波那契函式
阿新 • • 發佈:2018-12-03
題目(2018-11-15)
斐波那契數列指的是類似於下面的數列:
1, 1, 2, 3, 5, 8, 13, ……
也就是,第n
個數是由前面兩個數相加而來
完成fibonacci
函式,接受n
作為引數,可以獲取數列中第n
個數,例如:
fibonacci(1) // => 1
fibonacci(2) // => 1
fibonacci(3) // => 2
...
實現
想到的最簡單的實現就是利用遞迴:
const fibonacci = (n) => { if (n === 2 || n === 1) { return 1 } return fibonacci(n - 1) + fibonacci(n - 2) }
這樣的問題時,當n比較大的時候(比如500),計算時間過長,程式會失去響應
所以需要進行改進,需要利用快取,空間換區時間,在計算時多傳入一個cache
物件,用於快取計算過的資料:
const fibonacci = (n, cache = {}) => { if (n <= 2) { return cache[n] = 1; } if (cache[n]) { return cache[n]; } return cache[n] = fibonacci(n - 1, cache) + fibonacci(n - 2, cache) }; console.time('1st'); console.log(fibonacci(1000)); console.timeEnd('1st'); // 4.346655768693743e+208 // 1st: 1.26904296875ms console.time('2ed'); console.log(fibonacci(1000)); console.timeEnd('2ed') // 41 4.346655768693743e+208 // 2ed: 0.637939453125ms
通過實驗,這樣是行得通的。
我們還可以進一步優化,由於快取cache
在每次計算都是需要反問的,也就是說cache
是需要保留在記憶體中的,那麼我們就可以構造一個閉包,讓cache
保留在閉包中,供遞迴時使用:
const fibonacci = ((cache = {}) => n => { if (cache[n]) { return cache[n]; } if (n <= 2) { return cache[n] = 1; } return cache[n] = fibonacci(n - 1) + fibonacci(n - 2); })(); console.time('1st'); console.log(fibonacci(1000)); console.timeEnd('1st'); // 4.346655768693743e+208 // 1st: 0.6630859375ms console.time('2ed'); console.log(fibonacci(1000)); console.timeEnd('2ed') // 41 4.346655768693743e+208 // 2ed: 0.186279296875ms
多次試驗後發現,採用閉包的計算速度還是要快於直接傳參的計算速度的,尤其是非首次計算,相對於首次計算時,由於cache
會保留在記憶體中,對計算速度的提高非常大