原题链接
方法1:暴力递归(超时)
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if(triangle == null || triangle.size() == 0) return 0;
return helper(triangle, 0, 0);//需要处理的层和索引
}
private int helper(List<List<Integer>> triangle, int level, int index) {
if(level == triangle.size() - 1) return triangle.get(level).get(index);
int left = helper(triangle, level + 1,index);
int right = helper(triangle, level + 1,index + 1);
return triangle.get(level).get(index) + Math.min(left, right);
}
}
方法2:动态规划(自底向上)
二维数组 dp(i, j)表示 i 行 j 列元素到三角形底层的最小路径和。
DP方程:dp(i, j)= min( dp ( i+1, j),dp ( i+1, j+1)) + triangle(i, j)。
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
例如,4的最小路径和就等于 5 和 7 的最小路径和的较小者 + 4。显然 dp 数组最后一行的值,就是 triangle 最后一行的值。
public int minimumTotal(List<List<Integer>> triangle) {
if(triangle == null || triangle.size() == 0) return 0;
int lastRowSize = triangle.get(triangle.size() - 1).size();
int row = triangle.size();//行数
int[][] dp = new int[row][lastRowSize];//最大行,最大列
//初始化dp,最后一行的dp值就是triangle最后一行的值
for(int i = 0;i < lastRowSize;i++) {
dp[dp.length - 1][i] = triangle.get(row - 1).get(i);
}
for(int i = dp.length - 2; i >= 0; i--) {//从倒数第二行往上递推
for(int j = 0;j < i + 1;j++) {//第 i 行有 i + 1个元素
dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle.get(i).get(j);
}
}
return dp[0][0];
}
因为递推 第 i 行的 dp 值时,我们只需要第 i + 1 行的 dp 值,所以还可以优化为一维 dp
public int minimumTotal(List<List<Integer>> triangle) {
int row = triangle.size();//triangle有几行,单行最多就有几个元素
int[] dp = new int[row];
for (int i = 0; i < row; i++) dp[i] = triangle.get(row - 1).get(i); //初始化triangle的最后一行数组
for (int i = row - 2; i >= 0; i--) //从倒数第二行数组开始
for (int j = 0; j < i + 1; j++)
//在执行重写操作之前,dp[j]其实就是dp[i+1][j]
dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j);
return dp[0];
}