Leetcode Link: 64. 最小路径和 - 力扣(LeetCode)

题目

给定一个包含非负整数的 _m_ x _n_ 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:次只能向下或者向右移动一步。

解法一

从暴力递归到动态规划

显然属于位置依赖的模型。

暴力递归

子函数参数为当前的位置 x,y

只有两种情况,左走或者下走,需要考虑边界

base case 是走到右下角而不是走出去!

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        
        @functools.lru_cache()
        def process(x, y):
            if x == len(grid)-1 and y == len(grid[0])-1:
                return grid[x][y]
            
            res = float('inf')
            if y != len(grid[0])-1: # 边界判断
                res = min(res, process(x, y+1) + grid[x][y])
            if x != len(grid) - 1:
                res = min(res, process(x+1, y) + grid[x][y])
            return res
            
        return process(0, 0)

动态规划

该情况下,dp[x][y]表示的含义是从(x, y)到右下角的最小路径和

如果想直接想出dp,可以这样思考dp[x][y]的含义再写一个新的代码:从(0, 0)到(x, y)的最小路径和

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        # [x, y]
        dp = [[None for _ in range(len(grid[0]))] for _ in range(len(grid))]
        # init
        dp[len(grid)-1][len(grid[0])-1] = grid[len(grid)-1][len(grid[0])-1]
        # 可以先写最后一行和最后一列
        for x in range(len(grid)-2,-1,-1):  # 最后一列
            dp[x][len(grid[0])-1] = dp[x+1][len(grid[0])-1] + grid[x][len(grid[0])-1]
        for y in range(len(grid[0])-2,-1,-1):   # 最后一行
            dp[len(grid)-1][y] = dp[len(grid)-1][y+1] + grid[len(grid)-1][y]
 
        for x in range(len(grid)-2,-1,-1):
            for y in range(len(grid[0])-2,-1,-1): 
                dp[x][y] = min(dp[x+1][y], dp[x][y+1]) + grid[x][y]
        return dp[0][0]

还可以进一步做状态压缩。

启发和联系