逐层改进的斐波拉契数列--引入动态规划的思想

0x01.原始暴力递归方法

斐波拉契数列最原始的数学定义来源于递归,所以最开始是由递归解决斐波拉契问题的。代码如下:

int Fibonacci(int n)
{
	if (n == 1 || n == 2)
	{
		return 1;
	}
	return Fibonacci(n - 1) + Fibonacci(n - 2);
}

这个算法看起来很简单,但其实执行起来非常低效,为什么呢?

我们先来看一下这个时间复杂度,这个算法的时间复杂度主要由递归产生,每一次调用仅进行了加法和递归调用的操作,总共调用2的n次方次,那么这个时间复杂度是  O(2^{n}) O(n),指数级别,看到心头一颤。

我们仔细分析一下为什么效率低呢,按照常理来说,应该是只需要计算n次得。

我们模拟一下算法运行,加入传入50,那么先会递归调用49,48,49又会递归调用48,47,48又会递归调用46,47,,等等,你是不是已经发现了啥,没错,那就是48,47被反复得调用了,我们得目的最多只需要知道47,或者48,但是在这个递归调用得过程中,它被反复得调用了,这也就产生了很多不必要得重复,提升了时间复杂度,我们习惯称这种问题为:最小重叠子问题。

0x02.改进1--标记已求解

我们的想法是,如果把已经求出的中间问题标记起来,每当我们需要递归之前,先查询一下这个问题是否已经被解决,如果被解决,直接来拿用,如果没有,那么再进行递归,代码如下:

int Fibonacci(int n)
{
	if (n < 1)
		return 0;
	int *flag = (int*)calloc((n + 1),sizeof(int));//动态初始化一个数组
	return checker(flag, n);
}

int checker(int* flag, int n)
{
	if (n == 1 || n == 2)
		return 1;
	if (flag[n])//存在
		return flag[n];
	flag[n] = checker(flag,n-1) + checker(flag,n-2);//不存在则计算
	return flag[n];
}

这段代码充分实现了我们的想法,我们来计算一下时间复杂度。

因为这个算法不存在重复计算子问题的说法,所以,它的时间复杂度就是 O(n)。

0x03.改进2--一维基本动态规划

上述递归的做法是从n到1,2,既然有了这个思想,我们就可以从1,一直迭代到n,也就是基本动态规划的思想。

代码如下:

int Fibonacci(int n)
{
	int* dp = (int*)calloc(n, sizeof(int));
	if (n == 1||n==2)
		return 1;
	dp[0] = dp[1] = 1;
	for (int i = 2; i < n; i++)
	{
		dp[i] = dp[i - 1] + dp[i - 2];
	}
	return dp[n-1];
}

着就是最基础的一维动态规划,迭代关系可以从原始的递归过程中看出,由于是线性迭代,时间复杂度是 O(n)。

0x04.改进3--优化的动态规划

从时间复杂度上将,无可挑剔,不能再少了,但是从空间上来说,空间复杂度是 O(n)。

这个是否还可以优化呢?

答案是必然的,我们可以思考一下用这个长度为n的数组的目的,就是为了记录每一次迭代出来的值,但实际上我们使用了所有的值嘛,并没有,我们在一次循环中,只使用了两个dp数组中的值,这两个值其实是可以用变量来代替的,只需要不断的更新就行了,这样,空间复杂度就可以降为 O(1)。它也香~~~

代码如下:

int Fibonacci(int n)
{
	if (n == 1 || n == 2)
		return 1;
	int pre=1, cur=1;//前两次迭代的结果和前一次迭代的结果
	int sum;//本次的值
	for (int i = 2; i < n; i++)
	{
		sum = pre + cur;
		pre = cur;
		cur = sum;
	}
	return cur;
}

这个动态规划的算法已经优化到极致,不可以继续优化了,这样使用的动态规划,才是真的用好了动态规划!!!

0x05.从中得到的动态规划启示

  • 动态规划其实就是解决最小重叠子问题的一个方法。
  • 动态规划的关键是找准迭代表达式(也叫状态转移方程)和初始条件(也叫基准)。
  • 迭代表达式可以从递归中获取思路。
  • 初始条件往往是递归从后向前的结束条件。
  • 递归优化的过程,就是动态规划的逆向过程。
  • 动态规划的空间复杂度往往是可以考虑优化的。

如果本文对你有帮助,分享给更多朋友吧。

ATFWUS  --Writing By 2020--03--14  

  • 57
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值