题目:三角形最小路径和 middle
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是下标与上一层结点下标相同或者等于上一层结点下标 + 1 的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
package leetCode.DP;
import java.util.List;
public class lc_dp_120_minimumTotal {
/*
思路:
关键字:最小路径和-->dp
错误:
1.状态
1)最后一步
sum(n)=sum(n-1)+an
2)子问题
自顶向到n-1层的最小路径和
!!!这里出现问题!!!答案可能是到n-1层的路径和不一定会最小,但到(i,j)位置时和为最小
dp[i]表示自顶到i层的最小路径和
2.转移方程
dp[i]=dp[i-1]+min{ai,ai+1}
3.初始条件和边界条件
dp[0]=a0;
i-1>=0;
正确:
该三角形就是矩形的变种,要看成二维的
1.状态
1)最后一步
从a[i-1][j]到 a[i][j];sum[i-1][j]+a[i][j]
或从a[i-1][j-1]到 a[i][j];sum[i-1][j-1]+a[i][j]
2)子问题
求到(i-1,j)位置的最小路径和以及到(i-1,j-1)位置的最小路径和
所以dp应该是个二维数组,且dp[i][j]表示到(i,j)的最小路径和
2.转移方程
dp[i][j]=min{dp[i-1][j]+dp[i-1][j-1]}+a[i][j];
3.初始条件和边界条件
dp[0][0]=a[0][0];
i-1>=0;j-1>=0;
优化: 因为递推式只和前一行有关,dp可以优化成一维数组,初始版本为minimumTotal2
*/
// 因为递推式只和前一行有关,dp可以优化成一维数组
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[triangle.size()];
dp[0] = triangle.get(0).get(0);
int min = Integer.MAX_VALUE;
for (int i = 1; i < triangle.size(); i++) {
List<Integer> row = triangle.get(i);
// 每一行从后往前计算,如果从前往后,后面所需的dp[j-1]将不再是上一行的值,
// 会被替换成本行前一个的值,
for (int j = i; j >= 0; j--) {
//处理第一列的情况,第一列只能从dp[i - 1][j]到达
if (j == 0)
dp[j] = dp[j] + row.get(j);
//处理每行最后一个的情况,最后一个只能从dp[i - 1][j - 1]到达
else if (j == i)
dp[j] = dp[j - 1] + row.get(j);
else
dp[j] = Math.min(dp[j], dp[j - 1]) + row.get(j);
}
}
//遍历最后一行,找最小值
for (int i = 0; i < dp.length; i++) {
min = Math.min(min, dp[i]);
}
return min;
}
// 未优化版本
public int minimumTotal2(List<List<Integer>> triangle) {
int[][] dp = new int[triangle.size()][triangle.size()];
dp[0][0] = triangle.get(0).get(0);
int min = Integer.MAX_VALUE;
for (int i = 1; i < triangle.size(); i++) {
List<Integer> row = triangle.get(i);
for (int j = 0; j < row.size(); j++) {
//处理第一列的情况,第一列只能从dp[i - 1][j]到达
if (j == 0)
dp[i][j] = dp[i - 1][j] + row.get(j);
//处理每行最后一个的情况,最后一个只能从dp[i - 1][j - 1]到达
else if (j == i)
dp[i][j] = dp[i - 1][j - 1] + row.get(j);
else
dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + row.get(j);
}
}
//遍历最后一行,找最小值
int[] lastRow = dp[triangle.size() - 1];
for (int i = 0; i < lastRow.length; i++) {
min = Math.min(min, lastRow[i]);
}
return min;
}
}