动态规划与递归

这里借用leetcode的一道例题,来说一下动态规划和递归的区别

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

 例如,给定三角形:
 [
 [2],
 [3,4],
 [6,5,7],
 [4,1,8,3]
 ]
 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

  说明:
  如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

 

这种问题,一看就知道递归最简单了,但是这种递归方法其实就是一种暴力的全遍历破解,代码如下


//!递归函数
int recursive(vector<vector<int>>& triangle, int iVecIndex, int iInnerIndex)
{
	if (iVecIndex == triangle.size()-1)
	{
		return triangle[iVecIndex][iInnerIndex];
	}

	return min(recursive(triangle, iVecIndex + 1, iInnerIndex),
		recursive(triangle, iVecIndex+1, iInnerIndex + 1)) + triangle[iVecIndex][iInnerIndex];
}

//!调用主函数
int minimumTotalrec(vector<vector<int>>& triangle) {

	int iVecSize = triangle.size();
	if (iVecSize < 1 || triangle[0].size() < 1)
	{
		return 0;
	}

	return 	recursive(triangle, 0, 0);
}

递归的方式既简单,又容易理解,recursive参数为数组,一级数组的序列,二级数组中的序列。每调用一次就求得此位置到最终位置的最小和,终止条件为

递归条件为:sum(a[m][n]) = min(sum(a[m+1][n]), sum(a[m+1][n+1])) + a[m][n];

终止条件:n == triangle.size时(到达最底层时),直接返回此值。

当然递归带来的副作用很明显,效率太低,多次重复递归,

例如:

sum(a[4][2]) = min(sum(a[5][2]), sum(a[5][3)) + a[4][2];

sum(a[4][3]) = min(sum(a[5][3]), sum(a[5][4)) + a[4][3];

sum(a[4][4]) = min(sum(a[5][4]), sum(a[5][5)) + a[4][4];

上面时递归过程,很明显sum(a[5][3])和sum(a[5][4])重复递归两次,很明显我们递归了一些多余的信息。

这种情况如何去除冗余呢?

动态规划

动态规划应运而生,当子问题是父问题的解时,父问题由一个个子问题组成时,就用到了动态规划,与递归从顶到下的逻辑不同的时,动态规划是自底向上求解问题,每求得一个结果又可以组成上一级的结果,最终求得最优解,由于其自底向上,就保证了不会有多余的操作产生。那么下面就看一下解决此问题的动态规划算法:

//!动态规划
int minimumTotal(vector<vector<int>>& triangle) {

	int iVecSize = triangle.size();
	if (iVecSize < 1 || triangle[0].size() < 1)
	{
		return 0;
	}

	vector<int> vecToTal(iVecSize, 0);
	vecToTal[0] = triangle[0][0];

	//!正向规划
	for (int iIndex = 1; iIndex < iVecSize; iIndex++)
	{
		int iInnerVecSize = triangle[iIndex].size();
		//!初始值和最后值是固定的
		vecToTal[iInnerVecSize -1] = vecToTal[iInnerVecSize - 2] + triangle[iIndex][iInnerVecSize - 1];
		 //!其余比较特殊
		for (int iInnerIndex = iInnerVecSize - 2; iInnerIndex > 0; iInnerIndex--)
		{
			vecToTal[iInnerIndex] = min(vecToTal[iInnerIndex - 1], vecToTal[iInnerIndex])
				+ triangle[iIndex][iInnerIndex];
		}

		vecToTal[0] += triangle[iIndex][0];
	}

	int iMinValue = vecToTal[0];
	for (int iLastIndex = 1; iLastIndex < vecToTal.size(); iLastIndex++)
	{
		if (iMinValue > vecToTal[iLastIndex])
		{
			iMinValue = vecToTal[iLastIndex];
		}
	}

	return iMinValue;

}

上述算法,每次迭代的对应着从第一行到第n行各个点的最小距离,而到第n+1行的距离又可以通过到第n行的最短距离求得,依次迭代,知道迭代到最后一行,此时就求的从第1行到最后一行的各个点最短距离,此时只要求出最小值就可以得出所求解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值