关于斐波那契数列,你会几种呀!

488 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、…… ——百度百科

分析

斐波那契数列的一个数列:1,1,2,3,5,8,13,21,34,55,89...

划重点这个数列从第3项开始,每一项都等于前两项之和

2.webp

实现

递归

说!你是不是第一个想法也是递归实现..

function fibonacci1(n: number): number {
  if (n === 1 || n === 2) {
    return 1;
  }
  return fibonacci1(n - 1) + fibonacci1(n - 2);
}

测试

  1. fibonacci1(3); // => 2 ✅
  2. fibonacci1(5); // => 5 ✅
  3. fibonacci1(10); // => 55 ✅
  4. fibonacci1(100); // => 卒............

这个fibonacci1(100)直接让chrome 卒..., 原因最后再说.. 1.webp

尾递归调用

尾递归调用: 就是指在函数的最后一步调用自身函数

function fibonacci2(n: number, prev: number = 1, next: number = 1): number {
  if (n === 1 || n === 2) {
    return next;
  }
  return fibonacci2(n - 1, next, prev + next);
}

测试

  1. fibonacci2(3); // => 2 ✅
  2. fibonacci2(5); // => 5 ✅
  3. fibonacci2(10); // => 55 ✅
  4. fibonacci2(50); // => 12586269025 ✅
  5. fibonacci2(100); // => 354224848179262000000 ✅

循环

循环的算法逻辑:利用的是长度为3的滑块,【prev1(前2个),prev2(前一个),cur(当前)】, 依次向后移动,这样的好处就是只需要遍历一遍,cur的计算也是从之前的缓存结果中取到的。

function fibonacci3(n: number):number | undefined {
  if (n === 1 || n === 2) {
    return 1;
  }
  let prev1 = 1;
  let prev2 = 1;
  let cur = 0;
  for (let i = 3; i <= n; i++) {
    cur = prev1 + prev2;
    prev1 = prev2;
    prev2 = cur;
  }
  return cur;
}

  1. fibonacci3(3); // => 2 ✅
  2. fibonacci3(5); // => 5 ✅
  3. fibonacci3(10); // => 55 ✅
  4. fibonacci3(50); // => 12586269025 ✅
  5. fibonacci3(100); // => 354224848179262000000 ✅

数学通用公式

公式内容 image.png

function fibonacci4(n: number):number {
  if (n === 1 || n === 2) {
    return 1;
  }
  const SQRT_FIVE = Math.sqrt(5);
  return Math.round(1/SQRT_FIVE * (Math.pow(0.5 + SQRT_FIVE/2, n) - Math.pow(0.5 - SQRT_FIVE/2, n)));
}

测试

  1. fibonacci4(3); // => 2 ✅
  2. fibonacci4(5); // => 5 ✅
  3. fibonacci4(10); // => 55 ✅
  4. fibonacci4(50); // => 12586269025 ✅
  5. fibonacci4(100); // => 354224848179262000000 ✅

思考总结

为何递归fibonacci1(100);能到浏览器崩溃的地步...

递归算法分析 如图(图是盗的..🤭)

3.png 看的出来虽然递归写起来和理解起来很容易,但是会进行很多没必要的重复计算,导致运行时间超长.其时间复杂度达到了惊人的O(2^n).

另外:

  1. 尾递归调用的时间复杂度为O(n);
  2. 循环的时间复杂度为O(n);
  3. 数学通用公式的时间复杂度为O(logn);

所以,以后再实现斐波那契数列,你知道该选择哪一个了吗?

111.webp