斐波那契数列(兔子数列)
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
递归算法:
function f(n){
if (n<=2){
return 1;
}else{
//根据斐波那契数列递推的方法定义F(n)=F(n - 1)+F(n - 2)
return f(n-1)+f(n-2);
}
}
console.log(f(5));//当输入5时会打印5(打印当前输入第n个数的值)
//console.log(f(100));不要尝试
递归算法存在的问题:
1. 栈的大小是固定的,这也就意味着不能无限的递归。递归到某些时候,栈顶将会没有更多空间来添加新的栈顶,就像水杯容量是固定的,水杯满了就无法再添加了。
2. 递归需要做许多函数调用,每个函数调用都需要设置有一个栈帧,并传递参数,这些都增加了时间开销,即时间复杂度较高。
尾递归:
//num可以理解为 num为n-1 sum为n-2
function Fibonacci(n,num=1,sum=1){
//这里是对数列的打印
console.log(sum);
if (n<=2){
return sum;
}
//在结尾调用自己 (n自减一,sum传给num,num+sum传给sum)
return Fibonacci(n-1,sum,num+sum);
}
console.log(Fibonacci(8));
//console.log(Fibonacci(100));可以尝试
尾递归方法对递归算法进行的优化,因为编译器知道一旦执行了尾递归调用,就不需要先前的变量副本,因为没有更多的代码可以执行,降低了时间复杂度。
上述代码中还存在着一个问题:
输入的n值过大打印出来的数会失去精度。
解决办法:
ES2020 引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
如下代码:
function Fibonacci(n,num=1n,sum=1n){
// console.log(sum);
if (n<=2){
return sum;
}
return Fibonacci(n-1n,sum,num+sum);
}
console.log(Fibonacci(1000n));
//会输出43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875n(精确表示)
//没有用BigInt(大整数)则会输出4.346655768693743e+208(失去精度)