数据结构——斐波那契数列的那点事

引言

0、1、1、2、3、5、8、13、21

说来惭愧,第一次认识斐波那契数列是在一次面试题中,当时稍微观察了一下,就果断地写出了迭代版本的斐波那契数列…当时,还觉得这个算法题的数学模型也太简单了吧,殊不知有时候问题并不是你解决了就可以,毫无疑问对于斐波那契数列有多种解法,对于迭代版本的斐波那契数列来说它可能是多个版本中效率最高,但是我们并不能被迭代版本所限制住我们用编程解决问题的思维。

迭代版

既然最先提及迭代版本的斐波那契数列,那么我们就来看看它的实现:

function fibonacciInterative(n) {
		if (n < 1) return 0
		if (n <= 2) return 1

		let fibNMinus2 = 1
		let fibNMinus1 = 1
		let fibN = n
		for (let i = 3; i <= n; i++) {
			fibN = fibNMinus1 + fibNMinus2
			fibNMinus2 =fibNMinus1
			fibNMinus1 = fibN
		}
		return fibN
	}

其实,迭代版本的思路最白话地贴近我们的思路,首先对于索引为 0 1 的数值并没有规律,所以我们可以在方法中单独判断这种情况,返回对应的值(这里把索引为 2 的也加入,是因为都是返回 1,所以也无伤大雅一起返回),然后,对于其他的数学模型就很简单了,当前索引的值等于前两个索引的值之和,所以 for 循环遍历当前索引之前的数,一直求和以及赋值,最终求出当前索引下标对应的值。

递归版

对于递归,我想很多从事编程的同学都了解,但是目前我见到的很少场景会用到递归,除了早期在学数据结构的时候树用的比较多。不过,对于前端开发的同学我想对递归应该很是熟悉,因为 DOM 树 和 CSSOM 的缘故,在一些框架中设计 VNode 以及一些对象的时候都是树形结构,这个时候就避免不了递归遍历的过程。那么,我们来看看递归版的斐波那契数列:

function fibonacciRecursion(n) {
	if (n < 1) return 0
	if (n <= 2) return 1

	return fibonacciRecursion(n-2) + fibonacciRecursion(n - 1)
}

对比起来迭代版本,是不是感觉递归版本看起来简洁了许多。但是,仔细思考,会发现递归版本,会发生一种情况,由于它并没有存计算过的值,所以会出现重复计算相同索引地情况出现,这个过程无疑会浪费性能。

迭代+记忆版

了解了迭代,对于突然出现的名词记忆,我想大家可能会觉得有点突兀,其实对于记忆可以理解为缓存,通常是用一个数组来存一些值,然后避免重复计算或执行的过程(例如,在 Vue 中会缓存组件,避免组件的重复创建)。所以,迭代+记忆版的斐波那契数列会是这样的:

function fabonacciMemoization(n) {
	const memo = [0, 1]
	const fibonacci = (n) => {
		if (memo(n)) return memo(n)
		return memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
	}
	return fibonacci
}

对比起迭代版,记忆版避免了相同索引值的重复计算,并且和迭代版比起来,它也非常简洁,指得推荐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值