📅  最后修改于: 2023-12-03 15:35:53.117000             🧑  作者: Mango
在一个由数字组成的三角形中,从顶部出发,每一步可以向左下或右下走一层相邻的数字,直到走到底层,将沿途经过数字的和计算出来,求出所有路径中的最小值。
(1)动态规划
可以定义一个二维数组 $dp[i][j]$,表示从三角形的第一层走到第 $i$ 行,第 $j$ 列的数字的最小路径之和。根据题目的要求,最终的答案就是 $\min_{j=1}^{n}(dp[n][j])$,其中 $n$ 是三角形的高度。
为了方便计算,可以将三角形中的数字存储在一个二维数组 $triangle$ 中,其中 $triangle[i][j]$ 表示第 $i$ 行,第 $j$ 列的数字。
通过观察可知,三角形的第一行到第二行的转移非常容易,只需要将第二行的两个数字加上第一行的数字即可。而从第二行开始,每一个数字都有两个前驱数字,因此需要将前驱数字中的较小值加上当前数字。
具体的状态转移方程如下:
$$ dp[i][j] = \begin{cases} triangle[i][j] + dp[i-1][1] & j=1 \ triangle[i][j] + dp[i-1][j-1] & j=i \ triangle[i][j] + \min(dp[i-1][j-1],dp[i-1][j]) & \text{otherwise} \end{cases} $$
初始状态为 $dp[1][1] = triangle[1][1]$。
(2)空间优化
在上述动态规划的过程中,我们只需要维护前一行的状态即可计算当前行的状态,因此可以将二维数组 $dp$ 更改为一维数组 $prev$ 和 $curr$,通过交替使用这两个数组来进行计算。
以下是基于动态规划实现的 Python 代码:
def minimumTotal(triangle) -> int:
n = len(triangle)
prev, curr = [triangle[0][0]], [0] * n # 初始化 curr
for i in range(1, n):
curr[0] = prev[0] + triangle[i][0]
curr[i] = prev[i - 1] + triangle[i][i]
for j in range(1, i):
curr[j] = triangle[i][j] + min(prev[j - 1], prev[j])
prev, curr = curr, prev # 交换 prev 和 curr
return min(prev)
以下是空间优化后的代码:
def minimumTotal(triangle) -> int:
n = len(triangle)
prev = [triangle[0][0]] # 只需要维护前一行的状态
for i in range(1, n):
curr = [0] * n # 每次都要重新初始化 curr
curr[0] = prev[0] + triangle[i][0]
curr[i] = prev[i - 1] + triangle[i][i]
for j in range(1, i):
curr[j] = triangle[i][j] + min(prev[j - 1], prev[j])
prev = curr # 直接将 curr 赋值给 prev
return min(prev)
本题是典型的动态规划问题,在状态转移方程的推导中,需要仔细分析状态之间的关系。在实际编写代码时,考虑空间优化可以减小程序的空间复杂度,提高程序的运行效率。