class Solution:
def minimumTotal(self, triangle):
if not triangle:
return 0
for i in range(len(triangle) - 2, -1, -1):
for j in range(len(triangle[i])):
triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1])
return triangle[0][0]
for循环这里,我们从三角形的倒数第二行开始,逆向遍历至顶端。对于每一行的每个元素,我们都计算其下方相邻两个元素中的较小值,并将其累加到当前元素上。这样,triangle[i][j]
最终存储的就是从 (i, j)
位置到底部的最小路径和。
值得注意的是,由于我们是从下往上遍历的,所以每个元素在被更新时,其下方的元素值已经是最小路径和了。这确保了我们的计算是基于正确的值进行的。
这是我第一个成功的代码,虽然成功了,但是效率太低,执行用时长。按理来说采用了原地修改 triangle
数组(而非创建其副本)的策略来追踪从三角形顶端到底部的最小路径和,因为省去了额外的空间开销,所以效率应该更高。于是我再次运行了一次,出现了以下结果:
这里,让我们看一下官方题解给出的答案
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
f = [[0] * n for _ in range(n)]
f[0][0] = triangle[0][0]
for i in range(1, n):
f[i][0] = f[i - 1][0] + triangle[i][0]
for j in range(1, i):
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j]
f[i][i] = f[i - 1][i - 1] + triangle[i][i]
return min(f[n - 1])
作者:力扣官方题解
链接:https://leetcode.cn/problems/triangle/solutions/329143/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这里使用了一个二维数组 f
来存储从三角形顶端到当前位置的最小路径和。
接下来,从三角形的第二行开始(索引为1),我们遍历每一行和每一列,填充 f
数组。
- 对于每一行的第一个元素(即列索引为0),它只能从上一行的第一个元素到达,所以
f[i][0]
是f[i - 1][0] + triangle[i][0]
。 - 对于每一行的最后一个元素(即列索引为i),它只能从上一行的最后一个元素到达,所以
f[i][i]
是f[i - 1][i - 1] + triangle[i][i]
。 - 对于每一行的中间元素(即列索引在1到i-1之间),它们可以从上一行的相邻两个元素到达,所以
f[i][j]
是min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j]
。
这种方法的时间复杂度是 O(n2),其中 n 是三角形的行数(也是列数的最大值,对于等腰三角形而言)。
我突然发现点击蓝色柱状图可以直接看到不同用时的类似解法,如下图:
在我看到别人的代码之后,我发现我们的思路其实差不多,但是我的执行用时莫名比别人长,于是我尝试删除了自己的条件判断语句(实际中这个非空判断还是很需要的,不然没有错误处理容易出现问题)。删除之后执行用时直线下降,不过消耗内存略微上升,如下图:
这里是我刚开始写答案时的心路历程:我突然发现,我建立的dp是一个矩阵而不是三角形,我不确定这样行不行,所以我打算先这样写下去,将没有值的部分填充为0,这样不影响结果。或许dp应该是一个一维数组,因为每一行只选择一个数加入.这是第一次的代码,只有单行的成功了。
我觉得是返回值出了问题,可能是把赋初值时的0输出了。
修改后有值,但似乎只有前两排的和。
我想让它输出最后的和,但好像不应该用最大值,万一里面是复数呢。
我把代码改成了这样,并再一次尝试,但这次出现编译错误。有如下原因:
- 变量初始化:
n = len(triangle[0])
这个变量在后续代码中没有被使用。dp = [[0] * len(row) for row in triangle]
初始化了与triangle
相同形状的dp
数组,但这里应该直接从第二行开始填充,因为第一行直接等于triangle
的第一行。
- 逻辑错误:
if m>2: dp[1]=triangle[0][0]+min(triangle[1])
这行代码的逻辑是错误的。它试图将第二行的每个元素设置为基于第一行第一个元素和第二行最小元素的和,但这不是正确的动态规划转移方程。