【算法】动态规划-Fibonacci

Dynamic Programming

DP定义:

动态规划是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。

在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接使用这些结果。

动态规划具备了以下三个特点:

        1. 把原来的问题分解成了几个相似的子问题。
        2. 所有的子问题都只需要解决一次。
        3. 储存子问题的解。


动态规划的本质,是对问题状态的定义状态转移方程的定义(状态以及状态之间的递推关系)

动态规划问题一般从以下四个角度考虑:

        1. 状态定义
        2. 状态间的转移方程定义
        3. 状态的初始化
        4. 返回结果

状态定义的要求:定义的状态一定要形成递推关系。

一句话概括:三特点四要素两本质
适用场景:最大值/最小值, 可不可行, 是不是,方案个数


 第1题 Fibonacci

 斐波那契数列_牛客题霸_牛客网 (nowcoder.com)icon-default.png?t=M0H8https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=13&tqId=11160&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

答案-C/C++:

/*
 斐波那契数列定义:F(n)=F(n-1)+F(n-2)(n>=2,n∈N*),其中F(1)=1,F(2)=1
 方法一:递归
*/

class Solution {
public:
	int Fibonacci(int n) {
		// 初始值
		if (n <= 0) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		// F(n)=F(n-1)+F(n-2)
		return Fibonacci(n - 2) + Fibonacci(n - 1);
	}
};
/*
递归的方法时间复杂度为O(2^n),随着n的增大呈现指数增长,效率低下
当输入比较大时,可能导致栈溢出
在递归过程中有大量的重复计算
*/

/*
方法二:动态规划
状态:F(n)
状态递推:F(n)=F(n-1)+F(n-2)
初始值:F(1)=F(2)=1
返回结果:F(N)
*/
class Solution2 {
public:
	int Fibonacci(int n) {
		// 初始值
		if (n <= 0) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		// 申请一个数组,保存子问题的解,题目要求从第0项开始
		int* record = new int[n + 1];
		record[0] = 0;
		record[1] = 1;
		for (int i = 2; i <= n; i++) {
			// F(n)=F(n-1)+F(n-2)
			record[i] = record[i - 1] + record[i - 2];
		}
		return record[n];
		delete[] record;
	}
};
/*
上述解法的空间复杂度为O(n)
其实F(n)只与它相邻的前两项有关,所以没有必要保存所有子问题的解
只需要保存两个子问题的解就可以
下面方法的空间复杂度将为O(1)
*/
class Solution3 {
public:
	int Fibonacci(int n) {
		// 初始值
		if (n <= 0) {
			return 0;
		}
		if (n == 1 || n == 2) {
			return 1;
		}
		int fn1 = 1;
		int fn2 = 1;
		int result = 0;
		for (int i = 3; i <= n; i++) {
			// F(n)=F(n-1)+F(n-2)
			result = fn2 + fn1;
			// 更新值
			fn1 = fn2;
			fn2 = result;
		}
		return result;
	}
};

猜你喜欢

转载自blog.csdn.net/m0_51866180/article/details/122802365