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[i−1][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[i−1][j−1]+triangle[i][j],dp[i−1][j]+triangle[i][j]) ,jϵ[1,L−1)
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[i−1][i−1]+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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。