关于斐波那契数列

关于斐波那契数列

斐波那契数列 JS 实现

1
2
3
4
5
6
7
8
// n 默认为大于零的整数
function fib(n) {
	if (n < 2) {
		return n
	} else {
		return fib(n - 2) + fib(n - 1)
	}
}

斐波那契数列函数的实现基本是基于 “递归”  的思想。但是递归会涉及到一个比较严重的问题 “性能”!

性能分析

性能的主要问题是 “调用栈”,当我们递归调用函数的时候,上一个函数始终在执行栈内,无法弹出,导致调用栈不断增加,直到最后一个函数执行完毕,才会一个个一次回归弹出。

优化

优化的点主要在降低压栈次数或者计算次数。

尾递归优化

使用迭代代替递归,即尾递归。主要是在每次函数执行的时候弹出执行栈,返回一个新的函数继续后续执行,使得执行栈中始终只有一个函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function fib(n) {
	if (n < 2) {
		return n
	} else {
		return fib_in(2, n, 1, 0)
	}
}

function fib_in(start, end, pre1, pre2) {
	return start === end ? pre1 + pre2 : fib_in(start + 1, end, pre1 + pre2, pre1)
}

记忆函数

把递归改变成循环,对每次计算的结果进行缓存,避免斐波那契递归过程中大量的重复计算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function fib(n) {
	const arr = [0, 1]

	for (let i = 0; i < n; i++) {
		arr[i + 2] = arr[i + 1] + arr[i]
	}

	return arr[n]
}

// 或者

function fib(n) {
	let pre1 = 0
	let pre2 = 1
	for (let i = 0; i < n; i++) {
		temp = pre2
		pre2 = pre1 + pre2
		pre1 = temp
	}
	return pre1
}

延伸

我们优化斐波那契函数时,第二种方法是通过缓存结果来避免重复计算。同样的思想在 React 的优化中同样体现,React 的 memo 记忆函数,就是通过缓存相关变量,来避免组件的重复渲染。