leetcode-斐波拉契數列(js)

認識斐波拉契數列

第n 個數由數列的前兩個相加而來: f(n) = f(n - 1) + f(n -2),用代碼實現斐波拉契數列,無非就是要考察遞歸的寫法,但是,單純使用遞歸,在嚴格要求時間複雜度和空間複雜度上是不可行的,因爲他做了無數次無用的計算.

1, 1, 2, 3, 5, 8, 13, …

普通實現 (遞歸)

這種方式計算的時候會有很多重複的計算,而且遞歸的層數越來越深容易遞歸爆棧。

const fib = n => n <= 1 ? n :fib(n-1)+fib(n-2)
console.log(fib(5))

減少時間複雜度(閉包+遞歸)

通過增加一層緩存,用來存放之前已經計算過的數值,當需要計算新值的時候先通過查找緩存,緩存命中則直接返回,未命中再繼續計算。但是使用了數組,增加了空間複雜度.

const fib3 = function (n) {
  n <= 1 && n
  const cache = []
  cache[0] = 1
  cache[1] = 1
  function memoize(num) {
      if (cache[num] !== undefined) {
          return cache[num]
      }
      cache[num] = memoize(num - 1) + memoize(num - 2)
      // console.log(cache[num])
      return cache[num]
  }
  const result = memoize(n-1)
  return result
}
console.log(fib3(4))

但是這樣的實現方式有一個問題,如果不是依次計算斐波那契數列就會增加額外的消耗,比如直接計算 fib(1000) ,這個時候數組中會先初始化中間的其他數組項爲 undefined 這裏會小一些時間,但是計算完畢之後1-1000之間的斐波那契數列都填充完畢了。
參考網上的一種解法是用對象替換數組來進行緩存,這樣就少去了填充 undefined 的時間

// 閉包 + 緩存對象
const fibonacci = (function () {
  const f = {}
  return function(n) {
    if(n === 0 || n === 1) {
      return n
    }
    if(f[n-2] === undefined) {
      f[n-2] = fibonacci(n-2)
    }
    if(f[n-1] === undefined) {
      f[n-1] = fibonacci(n-1)
    }
    return f[n] = f[n-1] + f[n-2]
  }
})()

換一種從前往後算的寫法:::從前面的數一步一步的往後計算一直計算到n

const fib =function (n){
  n <= 1 && n
  const cache = []
  cache[0] = 1
  cache[1] = 1
  for (let i= 2; i<=n; i++ ) {
    cache[i] = cache[i-1] +cache[i-2]
  }
  return cache[n-1]
}
console.log(fib(5))

減少空間複雜度

不使用和數組,減少空間維度 從前往後算

const fib = n =>{
    n <= 1 && n
    let prev2 = 0
    let prev1 = 1
    let result = 0
    for (let i = 2;i<=n;i++) {
      result =prev2+prev1
      prev2 = prev1
      prev1 = result
    }
    return result
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章