一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
斐波那契数列是一种固定的算法。
示例:
0,1,1,2,3,5,8,13,21,34,55...
它的规律就是从第2项(从0项开始)开始,其值等于前两项之和,也就是f(n) = f(n-1) + f(n-2);
解题一
根据上方的公式,我们可以很快解出题目
//递归方法求
function fibonacci(n: number): number{
if(n <= 0) return 0;
if(n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2)
}
//功能测试
const fibonacciTest1 = fibonacci(10);
console.log(fibonacciTest1)//55 符合预期
上方代码就是完全按照公式写出来的,虽然它能够计算出结果,也满足题目的要求,但是这种递归的解题方式是十分消耗性能的,时间复杂度是十分高的O(2^n),所以在功能测试的时候使用较小的数字,千万不要因为好奇去尝试fibonacci(1000),甚至可能道110的时候,电脑的风扇就要开始咆哮了。
这张图片虽然只是绘制出一部分,但是相信大家已经能够看出这种递归方式为什么这么消耗性能了。所以,这种方法虽然能够解题,却是不可取的。
解题二
解题一为什么时间复杂度会那么的高呢?很大原因是因为每次都要去计算f(n-1) 和 f(n-2),那么能不能有什么办法将计算过的值记录下来呢?
我们来看一下这张图,当n<=0的时候,返回的肯定是0(设置变量为n2),当n==1的时候,返回的肯定是1(设置变量为n1),这两个是没办法使用公式计算的,所以先将这两个值记录下来,当n=2的时候,设置变量为res。f(n) = f(n-1) + f(n-2),也就是res = n1 + n2; 那么当n=2,计算完毕后,我们将 n1、n2整体后移,那么n2 = n1, n1 = res;这样一次执行是不是就可以得到n所对应的值呢?请看代码
//循环方法求斐波那契
function fibonacciFor(n: number): number{
if(n <= 0) return 0; //此时固定,无法利用公式计算,
if(n == 1) return 1;//此时固定,无法利用公式计算,
let res = 0;
let n1 = 1;//当n>1的时候,其表示的是n-2所对应的值;
let n2 = 0;//当n>1的时候,其表示的是n-1所对应的值;
//下方的循环从2开始,因为0,1已经写好了,而且公式中涉及到n-2,所以你最小是2;
for(let i = 2; i <= n; i++){
res = n1 + n2;
//整体后移
n2 = n1;
n1 = res;
}
return res;
}
//功能测试
const fibonacciTestFor = fibonacciFor(10);
console.log(fibonacciTestFor) //55 符合预期
解题二实际上就是对解题一做了优化,使用了循环代替递归,并且使用了动态规划的思想。解题二就将这道题目的时间复杂度由O(2^n)降低到了O(n);