斐波那契数列算法求解及速度

Posted lsaxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了斐波那契数列算法求解及速度相关的知识,希望对你有一定的参考价值。

斐波那契数,通常用  F(n) 表示,形成的序列称为斐波那契数列。该数列由  0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,   F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

给定  N,计算  F(N)。

 

 

第一种:

递归来解决,大多数人第一想法都是这样解决,包括我,Fibonacci(1) = 1, Fibonacci(2) = 1, 接下来Fibonacci(n) =  Fibonacci(n-1) + Fibonacci(n-2)就行

 1 function fib1 (n) {
 2   if (n === 1 || n ===2) {
 3     return 1;
 4   }
 5   return fib1(n - 2) + fib1(n-1);
 6 }
 7 
 8 console.time("测试递归斐波那契数列速度: ")
 9 console.log(fib1(40))
10 console.timeEnd("测试递归斐波那契数列速度: ")

真机实测递归40次:

技术图片

 

 

 实测50次等了一分钟没结果,就中断了。这种算法很明显不够好。每次递归都会调用一个栈进行计算,而重复的计算以及递归调用栈会占用大量内存。

第二种:

备忘录算法,这是对方文章写的一种算法,

文章原话:

这个 fib(1) 就是完全重复的计算,不应该为它再递归调用一次,而是应该在第一次求解除它了以后,就把他“记忆”下来。

把已经求得的解放在 Map 里,下次直接取,而不去重复结算。

这里用 iife 函数形成一个闭包,保留了 memo 这个私有变量,这是一个小技巧。

 1 let fib2 = (function () {
 2 let memo = new Map ();
 3 return function (n) {
 4 let memorized = memo.get(n);
 5 if (memorized) {
 6 return memorized
 7 }
 8 if (n == 1 || n == 2) {
 9 return 1;
10 }
11 let f1 = fib2(n-1)
12 let f2 = fib2(n-2)
13 
14 // 记录
15 memo.set(n-1, f1)
16 memo.set(n-2, f2)
17 
18 return f1 + f2
19 }
20 }) ()
21 
22 console.time("测试备忘录速度: ")
23 console.log(fib2(40))
24 console.timeEnd("测试备忘录速度: ")

真机实测:

技术图片

相比原始的递归速度快了很多。

第三种:

动态规划。

 1 let fib3 = function (N) {
 2   let dp = []
 3   dp[0] = 0
 4   dp[1] = 1
 5 
 6   for (let i = 2; i <= N; i++) {
 7     dp[i] = dp[i -1] + dp[i-2]
 8   }
 9 
10   return dp[N]
11 }
12 
13 console.time("测试 fn 速度: ")
14 console.log(fib3(1000))
15 console.timeEnd("测试 fn 速度: ")

这是一种神奇的想法,反其道而行,使用循环的想法来完成这个算法。

真机实测1000的,当然动态规划的速度还是由于第二种的。

技术图片

 

 

该文章引用掘金看了一篇作者晨曦时梦见兮的文章里面关于斐波那契数的三种解法。地址:https://juejin.im/post/5eae4453e51d454d980e392b

作者用青铜,白银,黄金三种算法来表达算法。当然这里不是照搬,而是加入了一些自己的思考。

 

第四种:

当然这还没完,这里产生出了一个想法,在第一种递归后,我想到了尾递归的处理方式。尾递归不像正常递归一样调用许多个调用帧,而是只有一个调用帧。所以时间复杂度大大缩减。所以这些我想比较下尾递归和动态规划的速度相差多少。

 1 function fib4 (n, ac1 = 1 , ac2 = 1) {
 2   if (n <= 2) {
 3     return ac2
 4   }
 5   return fib4 (n - 1, ac2, ac1 + ac2);
 6 }
 7 
 8 console.time("测试尾递归速度: ")
 9 console.log(fib4(1000))
10 console.timeEnd("测试尾递归速度: ")

实测:

技术图片

 

 最终得到结果为3>4>2>1

 
 

以上是关于斐波那契数列算法求解及速度的主要内容,如果未能解决你的问题,请参考以下文章

Python算法实验2-斐波那契数列

用递归和非递归方法求解斐波那契数列

斐波那契数列算法

斐波那契数列以及斐波那契数列的衍生形式 利用矩阵快速幂求解

数据结构与算法之深入解析“斐波那契数”的求解思路与算法示例

求解斐波那契数列复杂度分析