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
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
给出一个三角形,从顶端走向底端,经过路径的最短数字和是多少,每次只能走向相邻的数字。
原题是一个金字塔形的三角形,写成数组形式就变成了上述形状。
比如2可以走到3,4,3可以走向6,5
也就是说上一行j列到下一行可以走到j或者j+1
反之,j列的上一行可以是j或者j-1
思路:
每一行都求出上一行的数加下来的和,加的时候第j列的数选择上一行j和j-1中较小的相加
到最后一行求完后选择最小的那个值
(1) 二维DP
public int minimumTotal(List<List<Integer>> triangle) {
if(triangle == null || triangle.size() == 0) {
return 0;
}
int n = triangle.size();
//每行的元素数=行数,所以n行n列,补一行
int[][] dp = new int[n+1][n+1];
//后面用到取dp的min,所以先填上最大值
for(int i = 0; i <= n; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
for(int i = 1; i <= n; i++) {
//第i行元素只到i
for(int j = 1; j <= i; j++) {
dp[i][j] = triangle.get(i-1).get(j-1);
//第一行不需要和上一行相加,直接填入元素,不需要后续处理
if(i == 1 && j == 1) {
continue;
}
//边界条件
if(j == 1) {
dp[i][j] += dp[i-1][j];
} else if(j == i) {
dp[i][j] += dp[i-1][j-1];
} else {
dp[i][j] += Math.min(dp[i-1][j], dp[i-1][j-1]);
}
}
}
//array中的最大元素,java8
return Arrays.stream(dp[n]).min().getAsInt();
}
(2) 一维DP
因为每次只需要知道上一行的数,还需要保存当前行的数,因此只需要2行的dp数组
每次用dp[1][j]来求当前行的和,然后和dp的0行对换,作为下一次求dp[1]时的参考
c++中有简单的行对换的swap函数,还有求一行最小值的min_element函数
min_element返回iterator,所以用解引用操作符得到数值
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> dp(2, vector<int>(n, INT_MAX));
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
dp[1][j] = triangle[i][j];
if (i == 0 && j == 0) {
continue;
}
if (j == 0) {
dp[1][j] += dp[0][j];
} else if(j == i) {
dp[1][j] += dp[0][j - 1];
} else {
dp[1][j] += min(dp[0][j - 1], dp[0][j]);
}
}
std::swap(dp[0], dp[1]);
}
return *std::min_element(dp[0].cbegin(), dp[0].cend());
}
Java版
public int minimumTotal(List<List<Integer>> triangle) {
if(triangle == null || triangle.size() == 0) {
return 0;
}
int n = triangle.size();
//每行的元素数=行数,所以n行n列,补一行
int[][] dp = new int[2][n];
//后面用到取dp的min,所以先填上最大值
for(int i = 0; i <= 1; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
for(int i = 0; i < n; i++) {
//第i行元素只到i
for(int j = 0; j <= i; j++) {
dp[1][j] = triangle.get(i).get(j);
//第一行不需要和上一行相加,直接填入元素,不需要后续处理
if(i == 0 && j == 0) {
continue;
}
//边界条件
if(j == 0) {
dp[1][j] += dp[0][j];
} else if(j == i) {
dp[1][j] += dp[0][j-1];
} else {
dp[1][j] += Math.min(dp[0][j], dp[0][j-1]);
}
}
swapArr(dp[0], dp[1]);
}
//array中的最大元素,java8
//每次dp[1]中运算完之后要翻转到dp[0],因此最后看的是dp[0]
return Arrays.stream(dp[0]).min().getAsInt();
}
public void swapArr(int[] arr1, int[] arr2) {
//假设同一长度
for(int i = 0; i < arr1.length; i++) {
int tmp = arr1[i];
arr1[i] = arr2[i];
arr2[i] = tmp;
}
}
三角形最短路径算法
本文探讨了在给定的三角形结构中寻找从顶点到底部的最短路径和的算法实现。通过动态规划的方法,文章详细介绍了两种实现方式:二维DP和一维DP,以高效地解决这个问题。
754

被折叠的 条评论
为什么被折叠?



