原题链接: https://leetcode.com/problems/triangle/
1. 题目介绍
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
给出一个三角形,要从顶端向下走到最下面一行,只能沿着相邻的数字走。比如在第3行的5,只能到达下一行的1或者8,不能到达4、3。求数字和最小的路径。
最好使用O(n)的空间复杂度,n 为三角形的总行数。
2. 解题思路
求最优解的问题,一般都可以用动态规划来解决,这道题就是一道非常经典的动态规划题目。
2.1 空间复杂度O(n2) 的方法
使用一个二维数组dp[ n ][ n ]。n是三角形的总行数。dp[ i ][ j ]代表着到了第 i 行第 j 个数的位置时,累加的最小的和。
递归关系式为:
d
p
[
i
]
[
j
]
=
M
i
n
(
d
p
[
i
−
1
]
[
j
−
1
]
,
d
p
[
i
−
1
]
[
j
]
)
+
t
r
i
a
n
g
l
e
.
g
e
t
(
i
)
.
g
e
t
(
j
)
dp[i][j] = Min(dp[i-1][j-1] , dp[i-1][j] ) + triangle.get(i).get(j)
dp[i][j]=Min(dp[i−1][j−1],dp[i−1][j])+triangle.get(i).get(j)
其中 triangle.get( i ).get( j )是第 i 行第 j 个数。需要注意的是,在最左边和最右边的数字需要进行特殊判断,因为每一行的第一个数是没有dp[ i-1 ][ j-1 ]的,最后一个数是没有dp[ i-1 ][ j ]的。
实现代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
if(n == 0) {
return 0;
}
int dp[][] = new int [n][n];
dp[0][0] = triangle.get(0).get(0);
for(int i = 1;i<n;i++) {
for(int j = 0; j<=i ; j++) {
if(j == 0) {
dp[i][j] = dp[i-1][j] + triangle.get(i).get(j);
}
else if(j == i) {
dp[i][j] = dp[i-1][j-1] + triangle.get(i).get(j);
}
else {
dp[i][j] = Math.min(dp[i-1][j-1] , dp[i-1][j]) + triangle.get(i).get(j);
}
}
}
int ans = Integer.MAX_VALUE;
for(int i = 0;i<n;i++) {
if(dp[n-1][i] < ans) {
ans = dp[n-1][i];
}
}
return ans;
}
}
2.2 空间复杂度O(n) 的方法
思路和上面的方法一样,但是将二维数组转换成了一维数组。同样,因为二维数组在更新时,其实只用到了dp[ i-1 ][ j-1 ] , dp[ i-1 ][ j ]这两个数,其他的数都没有用到。那我们用一维数组也可以达到这个目的。 只不过每一行更新时,顺序要从后向前更新。
实现代码
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
if(n == 0) {
return 0;
}
int dp[] = new int [n];
dp[0]= triangle.get(0).get(0);
for(int i = 1;i<n;i++) {
for(int j = i; j>=0 ; j-- ) {
if(j == i) {
dp[j] = dp[j-1] + triangle.get(i).get(j);
}
else if (j == 0) {
dp[j] = dp[j] + triangle.get(i).get(j);
}
else {
dp[j] = Math.min(dp[j-1] , dp[j]) + triangle.get(i).get(j);
}
}
}
int ans = Integer.MAX_VALUE;
for(int i = 0 ; i<n ; i++) {
if(dp[i] < ans) {
ans = dp[i];
}
}
return ans;
}
}