DailyChallenge
120. 三角形最小路径和
Medium20200714
Description
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
❝如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
链接:leetcode-cn.com/problems/tr…
Solution
- 入门 二维dp数组
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int m = triangle.size();
int n = triangle.get(m - 1).size();
int[][] dp = new int[m + 1][n + 1];
int INF = Integer.MAX_VALUE / 4;
for(int i = 0; i < m; i++) Arrays.fill(dp[i], INF);
dp[0][0] = triangle.get(0).get(0);
for(int i = 1; i < m; i++){
for(int j = 0; j < triangle.get(i).size(); j++){
// System.out.println(triangle.get(i).size());
if(j == 0) dp[i][j] = dp[i - 1][j] + triangle.get(i).get(j);
else dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j);
// System.out.println(i+"\t"+j+"\t"+dp[i][j]);
}
}
int res = Integer.MAX_VALUE/4;
for(int j = 0; j < n; j++) res = Math.min(res, dp[m - 1][j]);
return res;
}
}
- 进阶,用一维dp数组
和0-1背包类似,如果改成一维dp数组,为了防止重复计算,就要从大到小遍历。
❝解释一下为什么从小到大遍历会有重复计算:
dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1])改成dp[j] = Math.min(dp[j], dp[j - 1]),如果j从小到大遍历,那么这个时刻的dp[j - 1]就是已经被上一次循环更新过的,因此二维表示应该是dp[i][j - 1]。这样不符合转移方程;如果j从大到小遍历,那么这个时刻的dp[j - 1]还未被更新过,因为它的二维表示是dp[i - 1][j - 1],这样才符合转移方程。
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int m = triangle.size();
int n = triangle.get(m - 1).size();
int[] dp = new int[n];
int INF = Integer.MAX_VALUE / 4;
Arrays.fill(dp, INF);
dp[0] = triangle.get(0).get(0);
for(int i = 1; i < m; i++){
for(int j = triangle.get(i).size() - 1; j >= 0 ; j--){
if(j == 0) dp[j] = dp[j] + triangle.get(i).get(j);
else dp[j] = Math.min(dp[j], dp[j - 1]) + triangle.get(i).get(j);
}
}
int res = INF;
for(int d : dp) res = Math.min(res, d);
return res;
}
}
❝我的公众号:GitKid
暂时每日分享LeetCode,我在不断学习的过程中,公众号也在不断充实,欢迎大家扫码关注。
TODO:动态规划专题
本文使用 mdnice 排版