算法思考(1)别再用递归计算斐波那契数列了!

曾经学习到递归时,相信绝大部分人都使用过斐波那契数列来学习递归吧。

当初我学习递归是老师还刻意让我们思考如何优化其性能,于是我们加了一些变量、参数 用于传递数据减少内存消耗,或者讲递归分割,分割成多个子递归最后挨个计算完了后进行合并。

但是!我当初学习时却被递归给局限住了,由于在学习递归,所以始终想的是如何用递归来实现,却忽略应当用最简便最高的方式来解决问题,直到今天我在一篇文章的评论区看到实用递归的斐波那契数列来测试计算性能是突然想到:斐波那契为啥要用递归,明明是个数组啊!就单数列而言数组也更家接近其结构吧...

正如《编程珠玑》第2版中提到的:结构决定算法,想这类结构已经有现成数据结构可以满足的数据显然应当优先考虑使用符合现有数据结构的计算方法才是更高效的,假如你正在学习或者你也和我一样曾经局限于算法->数据,那么不妨从此刻起尝试这换一种方式:数据决定算法的形式来进行编程。当然,更建议根据实际场景或者目标优先原则,在具体场景或目标实现了后尝试多方位尝试以寻求最优解为最终目标(前提你的老板能给你优化的时间,如果老板不给时间的话那就记录下吧?总比回头丢了忘了好吧)

以下实用数组实现的斐波那契方法:

const fibonacci = (n) => {
  if (typeof n !== 'number' || n <= 0) {
    throw new Error(`${n} must be a number greater than 0`);
  }
  if (n < 3) {
    return 1;
  } else if (n > 1476) {  // 最大值在 n 等于 1476 时,超过 1476 计算出来的值就已经超出 js 可表示的数值大小了,全部只能得到 Infinity
    return Infinity;
  }
  const resArr = new Array(n).fill(1);  // 省去初始化第一项和第二项了
  for (let i = 2; i < n; i++) {
    resArr[i] = resArr[i - 1] + resArr[i - 2];
  }
  return resArr[n - 1];
}

console.log(fibonacci(1476));  // 1.3069892237633987e+308
console.log(fibonacci(1477));  // Infinity

如果你需要大量使用的话,可以讲这里的 resArr 放到闭包中或者全局(不推荐),然后改进该方法使其在原本的 resArr 基础上如果 n 比之前大则 push 进去,如果比之前小则直接返回即可,但是相信大家也用不到几次吧,但是思路依然可以放到其他算法中,在使用频繁的计算耗时的算法建议使用数据缓存形式以降低平均耗时。

本人没有专门的进行算法学习,所以遇到这种思路可以记录一下,欢迎各位积极批评!

 

posted @ 2019-08-15 11:20  小马不黑  阅读(681)  评论(0编辑  收藏  举报