120. 三角形最小路径和_动态规划

120. 三角形最小路径和

1.题目描述

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.思路

(1)自顶向下的动态规划
开辟一个与triangle相同的dp二维数组。
状态定义: d p [ i ] [ j ] dp[i][j] dp[i][j]表示从顶点到第i行j列位置的最小路径和。
**边界:**第一行的值 就直接为其最小路径和。
**状态转移方程:**三角形中某行的值,计算分三种情况:1. 首位 直接与上方元素求和 2. 末位 直接与斜上方元素求和 3. 中间位 与上方相邻两元素分别求和 找出其较小值 为最小路径和。其公式: d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] + t r i a n g l e [ i ] [ 0 ] , i ϵ [ 1 , L ) dp[i][0]=dp[i-1][0]+triangle[i][0], i \epsilon [1, L) dp[i][0]=dp[i1][0]+triangle[i][0],iϵ[1,L) d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j − 1 ] + t r i a n g l e [ i ] [ j ] , d p [ i − 1 ] [ j ] + t r i a n g l e [ i ] [ j ] )   , j ϵ [ 1 , L − 1 ) dp[i][j]=min(dp[i-1][j-1]+triangle[i][j],dp[i-1][j]+triangle[i][j]) \ , j\epsilon [1, L-1) dp[i][j]=min(dp[i1][j1]+triangle[i][j],dp[i1][j]+triangle[i][j]) ,jϵ[1,L1) d p [ i ] [ i ] = d p [ i − 1 ] [ i − 1 ] + t r i a n g l e [ i ] [ i ] dp[i][i]=dp[i-1][i-1]+triangle[i][i] dp[i][i]=dp[i1][i1]+triangle[i][i]

代码:

// 最小三角形的和
int minimumTotal(vector<vector<int>>& triangle) {
	
	int n_line = triangle.size();  // 三角形行数

	// 定义dp数组
	vector<vector<int>> dp;
	vector<int> line_v;
	for (int i = 0; i < n_line; i++) {
		if (i == 0)
			line_v.push_back(triangle[0][0]);
		else {
			for (int ii = 0; ii < i + 1; ii++) line_v.push_back(0);
		}
		dp.push_back(line_v);
		line_v.clear();
	}
	

	// 状态转移方程
	for (int i = 1; i < n_line; i++)
		for (int j = 0; j < i+1; j++){
			// 某行 首数值
			if (j == 0){
				dp[i][0] = dp[i - 1][0] + triangle[i][0];
			}
			// 某行 中间数值
			if (j < i && j > 0) {
				dp[i][j] = min(dp[i - 1][j] + triangle[i][j], dp[i - 1][j - 1] + triangle[i][j]);
				//cout << dp[i - 1][j] + triangle[i][j] << endl;
				//cout << dp[i - 1][j - 1] + triangle[i][j] << endl;
			}
			// 某行 末位数值
			if (j == i)
				dp[i][j] = dp[i - 1][j - 1] + triangle[i][j];
		}

	// 找出末行最小值
	vector<int> last_line = dp.back();
	auto min = min_element(last_line.cbegin(), last_line.cend());

	return *min;

(2) 自底向上的动态规划方法
不需要要构造额外的内存空间,直接在原数组中进行操作。这种方法的思路简单、高效、巧妙。强烈推荐牛人的自底向上的方法。


[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
为例:
第一次对倒数第二行操作,6变成6+min(4,1)=7,5变成5+min(1,8)=6,7变成7+min(8,3)=10;这应该很好理解,当你选择的路径让你到达6时,接下来你可以选择4或者1,那么你自然会选择更小的1;当你选择的路径让你到达5时,接下来你可以选择1或者8,那么你自然会选择更小的1;当你选择的路径让你到达7时,接下来你可以选择8或者3,那么你自然会选择更小的3。
因此,可以把原来的lists变成
[
[2],
[3,4],
[7,6,10],
[4,1,8,3]
]
注意,因为我们是在原数组上进行操作,所以仍然保留了最后一行,但这不影响结果,因为我们最后会返回顶部的那个数,
继续向上操作,即操作倒数第三行,可以把lists变成
[
[2],
[9,10],
[7,6,10],
[4,1,8,3]
]
继续向上操作,即操作倒数第四行,可以把lists变成
[
[11],
[9,10],
[7,6,10],
[4,1,8,3]
]
最后,返回顶部的值。
作者:qiu-tian-hui-lai-liao
链接:https://leetcode-cn.com/problems/triangle/solution/zi-di-xiang-shang-dong-tai-gui-hua-lei-si-yu-cong-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值