LeetCode LCR 100. 三角形最小路径和
题目描述


题意分析
三角形第
i行有i + 1个元素。从(i, j)只能走到下一行的(i + 1, j)或(i + 1, j + 1),求从顶点走到底行的最小路径和。元素可以为负,路径仍必须走到底行,不能提前停止。进阶要求只用 $O(n)$ 额外空间,其中 $n$ 是行数。
解法:自底向上的三角形 DP
核心思路
[!blue]
定义
f[i][j]为从(i, j)出发走到底行的最小路径和。下一步只有两个合法位置,先选择它们较小的完整后续代价,再加上当前值,即f[i][j] = triangle[i][j] + min(f[i + 1][j], f[i + 1][j + 1])。比较的是后续整条路径的代价,不能只挑下一行眼前较小的数字。最后一行已经是终点,所以它的状态就是格子自身的值。由底向上处理时,第
i + 1行比第i行多一个元素,当前每个合法j的两个后继j、j + 1都存在,无需分别处理行首和行尾。每行只依赖下一行,用长度为
n的dp复制最后一行作为初值即可。从倒数第二行向上处理时,内层让j从 0 递增到i:赋值前,dp[j]和右侧的dp[j + 1]都尚未在本轮覆盖,仍是下一行的结果;把两者的较小值加当前值,写回dp[j]。处理完一行后,
dp[0..i]保存这一行的状态,更右侧的遗留值不再是后续所需范围。最终只有dp[0]表示从顶点出发的答案。初始化和转移都使用真实路径代价,不依赖非负性,因此负数也能正常参与比较。
解题步骤
- 创建长度为
n的数组,复制三角形最后一行。- 从
i = n - 2递减到 0,逐行向上处理。- 每行从
j = 0到i,将当前值加上min(dp[j], dp[j + 1])后写回。- 返回
dp[0];只有一行时,外层循环自然跳过。
代码实现
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[] dp = new int[n];
for (int j = 0; j < n; j++) {
dp[j] = triangle.get(n - 1).get(j);
}
for (int i = n - 2; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
// dp[j] 和 dp[j + 1] 是当前位置下一行能到达的两个选择。
dp[j] = triangle.get(i).get(j) + Math.min(dp[j], dp[j + 1]);
}
}
return dp[0];
}
}
func minimumTotal(triangle [][]int) int {
n := len(triangle)
dp := make([]int, n)
for j := 0; j < n; j++ {
dp[j] = triangle[n-1][j]
}
for i := n - 2; i >= 0; i-- {
for j := 0; j <= i; j++ {
// 从底向上更新,避免覆盖仍需要的状态。
if dp[j] < dp[j+1] {
dp[j] = triangle[i][j] + dp[j]
} else {
dp[j] = triangle[i][j] + dp[j+1]
}
}
}
return dp[0]
}
复杂度分析
- 时间复杂度:$O(n^2)$,初始化和转移合计处理三角形的 $n(n+1)/2$ 个元素。
- 空间复杂度:$O(n)$,只保存一行状态,且不修改输入三角形。
关键点总结
[!green]
- 状态是从当前格子到底行的完整最小和,答案位于顶点,而不是底行最小值。
- 滚动方向取决于需要读取旧状态还是新状态;本题两项都需下一行旧值,正序能保留右侧旧值。
- 最后一行必须计入路径,单行输入的答案就是该元素本身。
易错点总结
[!yellow]
- 本实现从倒数第二行开始转移,若将初始
dp全置 0,就会漏掉最后一行的代价。dp长度应为n,每行却只能处理j <= i,不能把整行缓冲区都当成当前三角形行。- 内层倒序会使
dp[j + 1]已变成本行值,混淆相邻两层。- 结束后不能取整个
dp的最小值,除dp[0]外的值只是下面各行遗留的状态。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 64. 最小路径和 | 中等 | 同样把每层最优结果传给下一层,本题相邻行长度不同且只能走到相邻两个位置。 |
| 931. 下降路径最小和 | 中等 | 同样是自上而下的最小下降路径,原题每格可选下方三个位置。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!