斐波那契数列指的是这样一个数列: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...... 这个数列从第3项开始,每一项都等于前两项之和。html
const fib1 = function(n) {
if (n > 1) return fib1(n - 1) + fib1(n - 2);
return n;
};
fib1(1000); // 个人 MacPro 电脑跑不出结果
复制代码
const fib1 = n => (n > 1 ? fib1(n - 1) + fib1(n - 2) : n);
fib1(1000); // 和上面同样
复制代码
我把 n 换成了 10, 打印了一下 fib1
函数的递归调用次数, 打印次数是177次;缓存
我又把 n 换成了 20, 打印了一下 fib1
函数的递归调用次数, 打印次数是21891次;markdown
那若是 n = 1000, 须要调用多少次呢? 有知道的小伙伴在评论区告诉我哈。app
刚才打印的时候,我发现有不少重复的调用, 好比 fib(1)
可能会调用不少次, 那么咱们是否能缓存一下fib(1)
的值呢?函数
若是已经求过 fib(1)
的值了,咱们会用一个 cache
变量缓存一下结果,下次调用的时候直接从缓存中取出来是否是就能够了!那么咱们开始吧!性能
const memozi = (_fib) => {
const cache = {};
return (n) => {
if (cache[n] === undefined) {
cache[n] = _fib(n);
}
return cache[n];
};
};
const fib2 = memozi(n => n > 1 ? fib2(n - 1) + fib2(n - 2) : n);
fib2(1000); //4.346655768693743e+208
复制代码
我尝试使用缓存的方式优化了一下递归调用, 计算的结果是 4.346655768693743e+208
学习
n = 10, 调用 11次优化
n = 20, 调用 21次spa
那么 n = 1000, 必定是调用了 1001 次。code
那么,通过咱们的优化以后,能快速的计算出 n = 1000的结果了, 计算耗时大概在 0.4ms
上下。
优化后的递归,计算速度已经很快了, 那么还有其余更快的方式吗?
const fib3 = (n) => {
let n1 = 0;
let n2 = 1;
let c = n1;
for (let i = 1; i <= n; i++) {
c = n1 + n2;
n2 = n1;
n1 = c;
}
return c;
}
fib3(1000); //4.346655768693743e+208
复制代码
这段代码使用了js 最基础的 for 循环实现, for 循环了 n 次, 计算耗时大概在 0.2ms
上下。
果真仍是 for 循环最实用哈。
1000 次耗时 | 2000 次耗时 | 时间 | |
---|---|---|---|
递归 | — | — | — |
优化递归 | 0.4ms | 0.65ms | O(n) |
for 循环 | 0.2ms | 0.22ms | O(n) |
今天咱们学习了 3 种方式实现斐波那契数列求解的方式
递归
调用次数太多,性能问题严重, 不适合实际使用, 可是一种理解递归易懂的方式。
优化递归
缓存已调用的递归函数, 下次使用时, 直接返回递归值的结果, 性能不错。
for 循环
使用变量赋值累加的方式, 把 n 赋值给 n - 1, 把 n - 1 赋值给 n - 2,遍历 n 次。
若是还有小伙伴知道比 for 循环更快的计算方式, 能够在下方的评论区跟我讨论哦。