120. 三角形最小路径和

中等 含交互动画

学完这道你应该能: 说清它为什么用「DP」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

三角形数组,每格只能走到下一行相邻两格,求顶到底的最小路径和

三角形 = [2] / [3,4] / [6,5,7] / [4,1,8,3]
输出 = 11
最优路径 = 2→3→5→1

思路解析

最直接的想法:从顶 2 出发,每格分叉走左/右,把所有路径都试一遍取最小。但路径条数随层数翻倍(n 层约 2ⁿ 条)。而且像中间那格 5,会被很多条不同路径反复经过、反复重算它「往下走到底的最小代价」——典型重叠子问题

换个状态定义:dp[j] = 站在某格、一路走到底的最小路径和。最底层每格走到底就是它自己。往上每格 = 自己 + min(正下方, 右下方),即 tri[i][j] + min(dp[j], dp[j+1])。为什么能记表?因为每格的答案只依赖下一行那两格,算好就存进 dp,上层直接查、不重算。自底向上还省去了对两条斜边的边界特判。

dp = 最后一行:先把 dp 初始化成三角形最后一行 [4, 1, 8, 3]:站在底层任一格,已经到底了,走到底的代价就是它自己。这一行 4 个值是后面所有计算的依赖来源,整张表固定 1 行 4 列、只覆盖数值不增删。

折叠行 [6,5,7] · 算 dp[0]:开始折入倒数第二行 [6,5,7]。第一格是 6:它正下方是 4、右下方是 1(蓝色两个依赖格),取较小的 1,dp[0] = 6+1 = 7。注意 4 没被选中——这就是"取 min"在做的事

折叠行 [6,5,7] · 算 dp[1]:第二格是 5:正下方 1、右下方 8,8 这条更大的路被丢弃,取 1,dp[1] = 5+1 = 6。每格都只保留通往底部更便宜的那一支。

折叠行 [6,5,7] · 算 dp[2]:第三格是 7:正下方 8、右下方 3,取 3,dp[2] = 7+3 = 10。这一行折完,dp 前三位变成 [7, 6, 10](最后一位 3 已用过、作废)。

折叠行 [3,4] · 算 dp[0]:折入第二行 [3,4]。第一格 3:正下方 7、右下方 6,取 6,dp[0] = 3+6 = 97 没被选——往左下走更贵。

折叠行 [3,4] · 算 dp[1]:第二格 4:正下方 6、右下方 10,取 6,dp[1] = 4+6 = 10。这一行折完,dp 前两位 = [9, 10]。

折叠顶 [2] · 算 dp[0]:最后折入顶点 2:正下方 9、右下方 10,10 那条更贵被舍弃,取 9,dp[0] = 2+9 = 11

答案:dp[0] = 11 就是最小路径和。整条最优路径 2→3→5→1,正好对应每一步选中的那个较小依赖格。

当「某格依赖下一行相邻几格」时,自底向上比自顶向下更顺:不用特判第一/最后一列,dp 还能一维原地滚动。下降路径最小和、堆叠 DP 都是这个套路。

参考代码(Python)

Python
1def minimumTotal(self, triangle):
2    dp = triangle[-1][:]                  # 复制最后一行做底层
3    for i in range(len(triangle) - 2, -1, -1):  # 倒数第二行往上
4        for j in range(len(triangle[i])):
5            dp[j] = triangle[i][j] + min(dp[j], dp[j+1])  # 自己+下方较小
6    return dp[0]

复杂度分析

  • 时间复杂度:O(n²) —— 三角形共约 n²/2 个格子,每格做一次 min 与相加
  • 空间复杂度:O(n) —— 只用一维 dp,长度等于底边 n

套路模板

记住骨架:dp 从最底层开始、逐层往上用相邻项聚合折叠。求最小用 min、求最大用 max,结构都一样。

Python
1dp = 最底层[:]                        # 从底层初始化
2for i in range(倒数第二层, -1, -1):
3    for j in range(本层宽度):
4        dp[j] = a[i][j] + 聚合(dp[j], dp[j+1])  # min / max / 加
5return dp[0]

易错点

  • 错误写法:dp = triangle[-1](直接引用最后一行)正确写法:dp = triangle[-1][:](复制一份)(不加 [:] 是同一个列表,原地折叠会改写、破坏原三角形数据)
  • 错误写法:自顶向下时忘了特判两条斜边正确写法:改用自底向上,每格恒有两个下方来源(顶向下时每行首尾格只有一个上方来源,少特判就会越界或漏路径)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →494. 目标和 ← 返回题库