斐波那契数列优化算法

最近看到斐波那契数列的算法,以为挺简单的,因而深刻研究了一下,发现算法其实还挺美妙的。
正常的fibonacci通常是这么算的:算法

function fibonacci(n) {
   if (n === 1 || n === 2) {
     return 1;
   }
   return fibonacci(n - 1) + fibonacci(n - 2);
 }

可是我在测试的时候发现,当n数值比较小的时候,这个函数性能还能够,运行时间也不慢,可是当n取30,40,60的时候,我电脑的CPU就淡定不了,这事我发现,它们所消耗的时间以下:数组

image.png

当计算到60的时候,耗费的时间为87.049s,不只时间太长,并且增长了CPU的压力,感受这个算法性能不是很好。这个算法的缺点就是会重复计算许屡次相同的f(n),好比要计算f(5),将会计算两次f(3),一次f(4),要是n取值更大的话,这些数值将会重复计算屡次,因而想减小重复计算。函数

优化方法一:利用数组标记计算过的f(n)

该方法的思路是定义一个长度为n的数组,n的每一项初始值为-1,当计算出每个f(n)的值时保存为a[n],这样下一次计算f(n)的时候,先从数组a中查看是否存在a[n]===-1,若arr[n] ===-1,则计算f(n),反之,则取a[n]的值。代码以下:性能

function fibonacci1(n) {
  var vArray = new Array(n+1);
   for(var index = 0;index <=n;index++){
        vArray[index] = -1;
    }
  return calcFn(n,vArray)
}
function calcFn(n,arr) {
    if (n === 1 || n === 2) {
      return 1;
    }
    if(arr[n] ===-1){
      // console.log(n)
      arr[n] = calcFn((n - 1),arr) + calcFn((n - 2),arr)
    }
    return arr[n]
}

计算结果:如下分别是n为30,40,60的计算结果测试

image.png

从上图来看,相对于第一种通用的方式,这个方法计算较大数值时,耗时明显缩短了,大大提升了运算速度。优化

优化方法二:a[n]=a[n-1]+a[n-2]

该方法的思路是,根据此通项的计算原理,a[n]=a[n-1]+a[n-2],咱们只须要保留a[n]的前两项,由f(1)=f(2)=1可知,咱们可初始化一个长度为2的数组a=[1,1],则f(3)=a[0]+a[1]=3,而后可将交换移动数组的的两项,好比计算完f(3)以后,a=[1,3],此时的数组a表明a[0] = f(2),a[1]=f(3),若我要计算f(4),则f(4)=a[0]+a[1],以此类推。代码以下:spa

function fibonacci2(n) {
  var arr = [1, 1];
  for(let i = 3; i <= n; ++i) {
      let temp = arr[1]
      arr[1] += arr[0]
      arr[0] = temp
  }
  return arr[1]
}

实验结果代表,此方法优化以后,计算耗时跟优化方法一差很少code

总结

两种优化的方法都能缩短计算耗时,均可以免同一数值屡次计算,二者的差别:blog

  • 方法一更容易理解,但代码不够简洁
  • 方法二代码简洁,思路比较灵活
  • 方法一须要定义一个长度跟n同样的数组,缺点是若n比较大,那这个数组的长度也会很大,且会保留每一项
  • 方法二只须要保留n-1,n-2两项,无论n为多大,只须要定义长度为2的数组,就可实现