算法入门07斐波那契数列

Posted 2021dragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法入门07斐波那契数列相关的知识,希望对你有一定的参考价值。

核心考点:空间复杂度,fib理解,剪枝重复计算

大家都知道斐波那契数列,现在要求输入一个正整数n,请你输出斐波那契数列的第n项。
斐波那契数列是一个满足

f i b ( x ) = { 1 x = 1 , 2 f i b ( x − 1 ) + f i b ( x − 2 ) x > 2 fib(x)=\\left\\{\\begin{matrix} 1 & x=1,2\\\\ fib(x-1)+fib(x-2)&x>2 \\end{matrix}\\right. fib(x)={1fib(x1)+fib(x2)x=1,2x>2

的数列。
​​​​​​​​​​​​​​​​​
解析一:(非常不提倡)

题目已经给出了斐波那契数列的状态转移方程,因此我们可以很容易使用递归的方式来求得第n个斐波那契数。

但如果使用递归来解决该问题,就不得不面对一个问题,那就是大量的重复计算,若是我们要得到第40个斐波那契数,那我们大致需要经历以下路径。

可以看到,图中对于同一斐波那契数进行了多次计算,而且越往下对于同一斐波那契数的重复计算次数越多,因此并不提倡使用递归的方法解决该问题。

//递归
class Solution {
public:
	int Fibonacci(int n) {
		if (n == 1 || n == 2) //fib(1)=1, fib(2)=1
			return 1;
		return Fibonacci(n - 1) + Fibonacci(n - 2); //fib(n)=fib(n-1)+fib(n-2)
	}
};

解析二:(不提倡)

既然使用递归存在大量的重复计算,那么我们可以考虑将已经计算过的斐波那契数保存起来,这样便避免了斐波那契数的重复计算。

例如,在计算第40个斐波那契数的中途需要计算第38个斐波那契数,而第38个斐波那契数已经被计算过了,那就无需再从此处递归下去了。

从图中看来就是不用再计算二叉树的某一枝叶了,因此该方法被形象的称为“剪枝”。

将递归和剪枝配合起来使用,其时间复杂度相比单纯的递归来说简直快了太多了,但该方法也有一个弊端,那就是需要额外的内存空间来暂时保存已经计算过的斐波那契数。

//递归+剪枝
class Solution {
private:
	unordered_map<int, int> filter; //存储已经计算过的斐波那契数
public:
	int Fibonacci(int n) {
		if (n == 1 || n == 2) //fib(1)=1, fib(2)=1
			return 1;

		int pper = 0; //第n-2个斐波那契数
		if (filter.find(n - 2) == filter.end())
		{
			//在map当中没有找到第n-2个斐波那契数,需要计算
			pper = Fibonacci(n - 2);
			filter.insert({ n - 2, pper });
		}
		else
		{
			//在map当中找到了第n-2个斐波那契数,直接获取
			pper = filter[n - 2];
		}

		int per = 0; //第n-1个斐波那契数
		if (filter.find(n - 1) == filter.end())
		{
			//在map当中没有找到第n-1个斐波那契数,需要计算
			per = Fibonacci(n - 1);
			filter.insert({ n - 1, per });
		}
		else
		{
			//在map当中找到了第n-1个斐波那契数,直接获取
			per = filter[n - 1];
		}

		return pper + per; //fib(n)=fib(n-1)+fib(n-2)
	}
};

解析三:(正解)

递归实际上是从终点看向起点,现在我们从起点看向终点,从第一个斐波那契数往后进行计算,需要第几个斐波那契数就计算到第几个。

而在该过程中我们不需要将所有计算过的斐波那契数全部保存起来,因为一个斐波那契数的值只与其前面两个斐波那契数有关。

我们任何时刻只需要保存蓝色方框当中的数据,可以看到蓝色方框的数据是时刻在变化的,因此该方法被形象的称为“动态规划”。

//动规
class Solution {
public:
	int Fibonacci(int n) {
		if (n == 1 || n == 2) //fib(1)=1, fib(2)=1
			return 1;
		int first = 1; //fib(1)=1
		int second = 1; //fib(2)=1
		int third = 0;
		while (n > 2) //进行n-2次计算
		{
			//fib(n)=fib(n-1)+fib(n-2)
			third = first + second;
			first = second;
			second = third;
			n--;
		}
		return third;
	}
};

以上是关于算法入门07斐波那契数列的主要内容,如果未能解决你的问题,请参考以下文章

用递归法计算斐波那契数列的第n项

C语言用递推和递归两种算法完成斐波那契数列的计算,给一下代码

斐波那契数列算法

斐波那契数列的实现算法

Python算法三种斐波那契数列算法

斐波那契数列(递归非递归算法)