pydata

Keep Looking, Don't Settle

leetcode 120. Triangle

120. Triangle

题目大意:给定一个triangle,找出从上到下的和的最小值,每一步只能找下一行的相连的数字

解题思路:经典动态规划题。假如找到了上一层的每个点的最小值,那么下一层的最小值可以通过上一层最小值得到。

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]

[
[2],
[5,6],
[11,10,13],
[15,11,18,16]
]

状态:\(f[i][j]\)表示走到第\(i\)行第\(j\)列的最小值

那么我们有

转移:\(f[i][j] = \mbox{min}(f[i - 1][j], f[i - 1][j - 1]) + \mbox{triangle}\)

def minimumTotal(self, triangle):
    n = len(triangle)
    # f[i][j] = min(f[i - 1][j], f[i - 1][j - 1]) + triangle
    # padding
    f = [[0 for _ in range(n + 1)] for _ in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, i + 1):
            f[i][j] = triangle[i - 1][j - 1]
            if i == 1 and j == 1:
                continue
            if j == 1:
                f[i][j] += f[i - 1][j]
            elif j == i:
                f[i][j] += f[i - 1][j - 1]
            else:
                f[i][j] += min(f[i - 1][j], f[i - 1][j - 1])
    return min(f[n][1:])

if __name__ == __main__:
    triangle = [[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]]
    Solution().minimumTotal(triangle)

因为\(f[i]\)只跟\(f[i-1]\)有关系,所有可以使用滚动数组来压缩空间。注意要使用deepcopy。

def minimumTotal(self, triangle):
    n = len(triangle)
    # padding
    # f[i][j] = min(f[i - 1][j], f[i - 1][j - 1]) + triangle
    f = [[0 for _ in range(n + 1)] for _ in range(2)]
    for i in range(1, n + 1):
        for j in range(1, i + 1):
            f[1][j] = triangle[i - 1][j - 1]
            if i == 1 and j == 1:
                continue
            if j == 1:
                f[1][j] += f[0][j]
            elif j == i:
                f[1][j] += f[0][j - 1]
            else:
                f[1][j] += min(f[0][j], f[0][j - 1])
        f[0] = f[1][:]
    return min(f[0][1:])

第三种办法,直接修改triangle,这样不需要额外的空间。因为直接修改triangle,所以不需要padding,注意相应的i和j的起始值也要改变。

def minimumTotal(self, triangle):
    n = len(triangle)
    t = triangle
    # t[i][j] = minTotalOf(i, j)
    # t[i][j] += min(t[i - 1][j], t[i - 1][j - 1])
    for i in range(0, n):
        for j in range(0, i + 1):
            if i == 0 and j == 0:
                continue
            if j == 0:
                t[i][j] += t[i - 1][j]
            elif j == i:
                t[i][j] += t[i - 1][j - 1]
            else:
                t[i][j] += min(t[i - 1][j], t[i -1][j - 1])
    return min(t[n - 1])