1. 使用generator函数和for of循环实现斐波那契数列;
1 // 使用generator函数和for of循环实现斐波那契数列;
2 /**
3 * @function fibNumbers
4 * @description 生成斐波那契数列的函数
5 * @param {number} num 表示要生成最大数不超过num的斐波那契数列
6 * @return 返回值一个斐波那契数列的数组
7 */
8 function fibNumbers(num) {
9 function* fibonacci() {
10 let [prev, curr] = [0, 1];
11 for (;;) {
12 yield curr;
13 [prev, curr] = [curr, prev + curr];
14 }
15 }
16 const numbers = [];
17 for (let n of fibonacci()) {
18 if (n > num) break;
19 // console.log(n);
20 numbers.push(n);
21 }
22 return numbers;
23 }
24 const fibonacciArr = fibNumbers(50);
25 // 输出: [1, 1, 2, 3, 5, 8, 13, 21, 34]
2. 使用递归和for循环求第n个斐波那契数:
1 // 计算第n个斐波那契数是多少的函数
2 // 1.for循环方式,速度最快
3 function fibonacciByFor(n) {
4 if (n === 1 || n === 2) {
5 return 1;
6 }
7 let [pre, cur] = [1, 1];
8 // 如果是以下标计算,for循环中第二个语句为 (i <= n;)
9 for(let i = 2;i < n;i++){
10 // 1.1 一般的写法, 执行耗时最短
11 const sum = pre + cur;
12 pre = cur;
13 cur = sum;
14 // 1.2 解构赋值的写法
15 // [pre, cur] = [cur, pre + cur];
16 }
17 // console.log(`第${n}个斐波那契数为:`, cur);
18 return cur;
19 }
20 console.time('for循环斐波那契');
21 fibonacciByFor(20); // 输出:6765, 耗时:0.06689453125 ms
22 console.timeEnd('for循环斐波那契');
23
24 // 2.递归方式,性能没有for循环好
25 // 2.1 普通递归
26 // 如果n为5,则会重复计算fibByRecursion(4)两次
27 // n越大则重复计算的次数越多,
28 // 这样会导致堆栈溢出, 浏览器出现假死状态,导致无法及时计算出结果(当值设置为50的时候就很明显了)
29 function fibByRecursion(n) {
30 if (n === 1 || n === 2) {
31 return 1;
32 }
33 return fibByRecursion(n - 2) + fibByRecursion(n - 1);
34 }
35 console.time('普通递归');
36 fibByRecursion(20); // 输出:6765, 耗时:1.19287109375 ms
37 console.timeEnd('普通递归');
38
39 // 2.2 递归改进1,避免重复计算
40 function fibByRecursion1(n) {
41 // 把前后两位数作为参数,在传递参数时进行计算
42 return fib(n, 1, 1);
43 function fib(n, pre, cur) {
44 if (n === 1) {
45 return pre;
46 }
47 if (n === 2) {
48 return cur;
49 }
50 return fib(n - 1, cur, pre + cur);
51 }
52 }
53 console.time('递归改进1');
54 fibByRecursion1(20); // 输出:6765, 耗时:0.0888671875 ms
55 console.timeEnd('递归改进1');
56
57 // 2.3 递归改进2,使用闭包的作用域特性把计算的结果存储在数组中,避免了重复计算
58 function fibByRecursion2(n) {
59 let initMembers = [0, 1];
60 return fib(n);
61 function fib(n) {
62 if (initMembers[n] === undefined) {
63 // 把不存在的项存到数组中,下次再找到当前存储的第n项时就不会重新计算了
64 initMembers[n] = fib(n - 2) + fib(n - 1);
65 }
66 return initMembers[n];
67 }
68 }
69 console.time('递归改进2');
70 fibByRecursion2(20); // 输出:6765, 耗时:0.091796875 ms
71 console.timeEnd('递归改进2');
72
73 // 2.4 递归改进3,提取fibByRecursion2中的存储计算结果的功能函数
74 function fibByRecursion3(n) {
75 let fib = setMemory(function (n) {
76 if (n === 1 || n === 2) {
77 return 1;
78 }
79 return fib(n - 2) + fib(n - 1);
80 });
81 return fib(n);
82 // 将存储功能提取到一个函数中
83 function setMemory(fn) {
84 let memorizer = [];
85 return function (n) {
86 if (memorizer[n] === undefined) {
87 memorizer[n] = fn(n);
88 }
89 return memorizer[n];
90 }
91 }
92 }
93 console.time('递归改进3');
94 fibByRecursion3(20); // 输出:6765, 耗时:0.092041015625 ms
95 console.timeEnd('递归改进3');
3. 参考链接:
3.1 JS写斐波那契数列的几种方法;
3.2【java】递归次数过多导致堆栈溢出;