js斐波那契数列及递归栈溢出问题

什么是斐波那契数列

诸如1,1,2,3,5,8,13....这样的序列,除了前两个固定是1(原因见<不死神兔>典故)从第三个开始每个数等于前两个数的和

也就是n = (n-1)+(n -2) (n>=3)

递归实现

第一个: 1

第二个: 1

第三个: 2

第四个: 3

......

按照这个规律 因为前两个始终都是1 所以我们确定了递归的出口就是 n===1和2时结果为1 每次递归就是求前两项的和

        function feibonaqi(n) {
          if (n === 1 || n === 2) {
            return 1
          }
          return feibonaqi(n - 1) + feibonaqi(n - 2)
        }

当n超过45时,浏览器就没有反应了,转啊转,赶紧关了...

因为第n个等于n-1+n-2的和,n-1又等于n-2+n-3的和,以此类推,存在大量的重复计算,此时我们要优化递归了,将结果用哈希表以n为key缓存起来所有的n-1+n-2

优化递归实现加缓存

      const cache = new Map()
      function feibonaqiMemo(n) {
        if (n === 1 || n === 2) {
          return 1
        }
        // 如果缓存有优先从缓存拿 没有就将结果存入缓存
        return (
          cache.get(n) ||
          cache.set(n, feibonaqiMemo(n - 1) + feibonaqiMemo(n - 2)).get(n)
        )
      }
      console.log(feibonaqiMemo(1000))

经过缓存后求1000的斐波那契数速度都非常快了,类似这样缓存的思想我们可以服用成一个缓存函数,返回一个具备缓存结果能力的缓存函数

实现缓存函数

这里可以采用闭包来存储缓存的结果

      function memo(fn) {
        const cache = new Map() // 缓存结果
        return function (...args) {
          const key = JSON.stringify(args) // 将入参做为key
          // 优先从缓存取,没有则存入缓存
          return cache.get(key) || cache.set(key, fn.apply(null, args)).get(key)
        }
      }
      const feibonaqiMemo = memo(function (n) {
        if (n === 1 || n === 2) {
          return 1
        }
        return feibonaqiMemo(n - 1) + feibonaqiMemo(n - 2)
      })
      console.log(feibonaqiMemo(1000))

当n比较大时,比如n=4000,递归会出现栈溢出问题,递归基本上都是可以用循环替代的,我们可以用循环替代递归解决栈溢出的问题

循环实现

      function feibonaqiViaLoop(n) {
        const arr = [] // 用数组来存储每个n的斐波那契数
        arr[0] = arr[1] = 1 // 前两个都是1直接存储
        // 从第三个开始 n = n-1+n-2
        let i = 2
        while (i < n) {
          arr[i] = arr[i - 1] + arr[i - 2]
          i++
        }
        return arr[n - 1] // 返回第n个也就是最后一个数
      }
      console.time('feibonaqiViaLoop')
      console.log('n=9999999:', feibonaqiViaLoop(9999999))
      console.timeEnd('feibonaqiViaLoop')

 这样n再大也能运行了,但是这个结果太大了所以infinity了,所以能用循环解决时尽量避免用递归

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值