欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

动态规划经典题目之三 斐波那契数列

程序员文章站 2022-04-08 13:54:49
...

问题描述

斐波那契数列 1 1 2 3 5 8 ... ... 求斐波那契数列的第n项和。

问题分析

    斐波那契数列的递推公式为 F(n) = 1,n=1,2; F(n) = F(n - 1) + F(n - 2), n >= 3;

采用递归的方式很容易写出代码,但是递归的代码虽然简单,却存在着大量的重复子问题,重复计算,时间复杂度高。例如,我们以求解F(5)为例,如下:

动态规划经典题目之三 斐波那契数列

红色的部分都是重复求解的,这仅仅是n=5时,当n=30时,子结构重复求解会大大浪费时间,时间,空间都会爆掉。

                          

解法1:

    我们直观想到的是,既然会重复求解,那只要记录下来求解过的就行了,下次计算前,先看看有没有计算过,如果已经计算过就不需要再次计算,这就是备忘录算法。但是,当n过大时,递归层数过多,空间也会爆掉。

 

解法2:

    解法1是自顶向下进行递归求解。而DP是自底向上的求解问题,由初始状态一步步向上求的问题的解。对于斐波那契数列,初始状态为 F(1) = F(2) = 1, 那么我们可以依次求出 

F(3),F(4),... ...F(n) ,同样的子问题,也是只需要求解一次,大大提高了计算效率。

递归求法代码

#include <iostream>

using namespace std;

int fib(int N)
{
    if(N == 1)
        return 1;
    ifa(N == 2)
        return 1;
    return fib(N-1) + fib(N-2);
}

int main()
{
    int n;
    cin >> n;
    cout << fib(n) << endl;
}

备忘录算法

#include <iostream>

using namespace std;

int* fib_data;

int fib(int N)
{
	if(N == 1)
		return 1;
	if(N == 2)
		return 1;
	if(fib_data[N] > 0)
		return fib_data[N];
	else {
		fib_data[N-1] = fib(N-1);
		fib_data[N-2] = fib(N-2);
		return fib_data[N-1] + fib_data[N-2];
	}
}

int main()
{
	int n;
	cin >> n;
	fib_data = new int[n + 1];
	memset(fib_data,0,sizeof(int) * (n + 1));
	cout << fib(n) << endl;
}

DP代码

#include <iostream>

using namespace std;

long long dp_fib(int N)
{
	long long* fib_n = new long long[N + 1];
	fib_n[1] = 1;
	fib_n[2] = 1;
	for (int i = 3; i <= N; i++) {
		fib_n[i] = fib_n[i - 1] + fib_n[i - 2];
	}
	return fib_n[N - 1];
}

int main()
{
	int n;
	cin >> n;
	cout << dp_fib(n) << endl;
}