Leetcode 120. 三角形最小路径和
题目描述
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
解题思路
动态规划,用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示从顶点到达
(
i
,
j
)
(i, j)
(i,j)点的最短路径和。状态转移方程如下:
d
p
[
i
]
[
j
]
=
{
t
r
i
a
n
g
l
e
[
i
]
[
j
]
i
=
0
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
]
j
=
0
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
−
1
]
j
=
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
1
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
m
i
n
{
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
1
]
}
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
1
>
j
>
0
dp[i][j]= \left \{ \begin{array}{lr} triangle[i][j]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i=0\\ triangle[i][j]+dp[i-1][j]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=0\\ triangle[i][j]+dp[i-1][j-1]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=triangle[i].length-1\\ triangle[i][j]+min\{dp[i-1][j],dp[i-1][j-1]\}\ \ \ \ triangle[i].length-1>j>0 \end{array} \right .
dp[i][j]=⎩⎪⎪⎨⎪⎪⎧triangle[i][j] i=0triangle[i][j]+dp[i−1][j] j=0triangle[i][j]+dp[i−1][j−1] j=triangle[i].length−1triangle[i][j]+min{dp[i−1][j],dp[i−1][j−1]} triangle[i].length−1>j>0
可以看出来,更新第
i
i
i行只需要用到第
i
−
1
i-1
i−1行,所以可以进一步优化空间。
用
d
p
[
j
]
dp[j]
dp[j]表示从顶点到达
(
i
,
j
)
(i, j)
(i,j)点的最短路径和,优化之后的公式如下:
d
p
[
j
]
=
{
t
r
i
a
n
g
l
e
[
i
]
[
j
]
i
=
0
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
d
p
[
j
]
j
=
0
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
d
p
[
j
−
1
]
j
=
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
1
t
r
i
a
n
g
l
e
[
i
]
[
j
]
+
m
i
n
{
d
p
[
j
]
,
d
p
[
j
−
1
]
}
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
1
>
j
>
0
dp[j]= \left \{ \begin{array}{lr} triangle[i][j]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i=0\\ triangle[i][j]+dp[j]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=0\\ triangle[i][j]+dp[j-1]\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=triangle[i].length-1\\ triangle[i][j]+min\{dp[j],dp[j-1]\}\ \ \ \ triangle[i].length-1>j>0 \end{array} \right .
dp[j]=⎩⎪⎪⎨⎪⎪⎧triangle[i][j] i=0triangle[i][j]+dp[j] j=0triangle[i][j]+dp[j−1] j=triangle[i].length−1triangle[i][j]+min{dp[j],dp[j−1]} triangle[i].length−1>j>0
其中,
i
=
{
0
,
1
,
2
,
.
.
.
,
n
−
1
}
i=\{0,1,2,...,n-1\}
i={0,1,2,...,n−1}
j
=
{
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
1
,
t
r
i
a
n
g
l
e
[
i
]
.
l
e
n
g
t
h
−
2
,
.
.
.
,
0
}
j=\{triangle[i].length-1, triangle[i].length-2,...,0\}
j={triangle[i].length−1,triangle[i].length−2,...,0}
注意,
j
j
j必须是降序,这是因为求
d
p
[
j
]
dp[j]
dp[j]需要用到
d
p
[
j
−
1
]
dp[j-1]
dp[j−1]。如果求
d
p
[
j
]
dp[j]
dp[j]需要用到
d
p
[
j
+
1
]
dp[j+1]
dp[j+1],则
j
j
j需要是升序。
代码实现
不带空间优化
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int dp[1050][1050] = {0};
int n = triangle.size();
if (n == 0) return 0;
if (triangle[0].size() == 0) return 0;
dp[0][0] = triangle[0][0];
for (int i = 1; i < n; i++) {
for (int j = 0; j < triangle[i].size(); j++) {
if (j == 0) {
dp[i][j] = dp[i-1][j] + triangle[i][j];
}
else if (j == triangle[i].size()-1) {
dp[i][j] = dp[i-1][j-1] + triangle[i][j];
}
else {
dp[i][j] = triangle[i][j] + min(dp[i-1][j], dp[i-1][j-1]);
}
}
}
int ans = dp[n-1][0];
for (int j = 1; j < triangle[n-1].size(); j++) {
ans = min(ans, dp[n-1][j]);
}
return ans;
}
};
空间优化
class Solution {
public:
int minimumTotal(vector<vectot<int>>& triangle) {
int dp[1050] = {0};
int n = triangle.size();
if (n == 0) return 0;
if (triangle[0].size() == 0) return 0;
dp[0] = triangle[0][0];
for (int i = 1; i < n; i++) {
for (int j = triangle[i].size()-1; j >= 0; j--) {
if (j == 0) {
dp[j] = dp[j] + triangle[i][j];
}
else if (j == triangle[i].size()-1) {
dp[j] = dp[j-1] + triangle[i][j];
}
else {
dp[j] = triangle[i][j] + min(dp[j], dp[j-1]);
}
}
}
int ans = dp[0];
for (int j = 1; j < triangle[n-1].size(); j++) {
ans = min(ans, dp[j]);
}
return ans;
}
};