给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 ii + 1

示例 1:

1
2
3
4
5
6
7
8
输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
2
3 4
6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

示例 2:

1
2
输入:triangle = [[-10]]
输出:-10

思路

贪心算法

此题很容易想到使用贪心算法求解,既从顶点开始,每一步都选择值最小的点向下前进。在示例提供的数据中这种算法可以找到最优解。但需要考虑在一些情况下,贪心算法仅能找到局部最优解,例如:

1
2
3
4
5
   2
3 4
8 9 1
7 6 5 2
本例使用贪心算法获取的路径为:(2-3-8-6)但实际最优解为(2-4-1-2)

动态规划

这道题目其实类似于背包问题,天然适用与动态规划,甚至于我们可以直接在现有的三角形上构建动态规划矩阵。核心思路为:

  • 计算第一行节点的最小路径和(其实就是数字本身,不用做处理)
  • 从第二行开始,根据当前行与上一行,计算到每一行各个节点的最小路径和
  • 找到最后一行中最小的路径和节点,即为这个三角形的最小路径和

例如刚才提到的三角形:

1
2
3
4
   2
3 4
8 9 1
7 6 5 2

计算第二行

1
2
3
4
  (2)
(5 6)
8 9 1
7 6 5 2

计算第三行

1
2
3
4
5
   (2)
(5 6)
(13 14 7)
7 6 5 2
其中,9这个节点既可从5到达,也可从6到达,我们只需计算最小从5到达的路径和即可

计算最后一行

1
2
3
4
    (2)
(5 6)
(13 14 7)
(20 19 12 9)

通过取最后一行的最小值,即可获取最小路径和:9

题解

思路清晰之后直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
for coloumIndex,row in enumerate(triangle):
if coloumIndex>0:
# 最左边元素仅可从上一行的最左边元素到达
row[0] += triangle[coloumIndex-1][0]
# 最右边元素仅可从上一行最右边元素到达
row[-1] += triangle[coloumIndex-1][-1]
# 其余元素可从上一行的2个元素到达,取最小计算路径和
for i in range(1,coloumIndex):
row[i]+=min(triangle[coloumIndex-1][i-1],triangle[coloumIndex-1][i])
# 返回最后一行中最小的路径和
return min(triangle[-1])