📜  三角形中的最小求和路径(1)

📅  最后修改于: 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)
总结

本题是典型的动态规划问题,在状态转移方程的推导中,需要仔细分析状态之间的关系。在实际编写代码时,考虑空间优化可以减小程序的空间复杂度,提高程序的运行效率。