LeetCode64 最小路径和

25 阅读2分钟

leetcode.cn/problems/mi…

image.png

解法一:自顶向下的递归dp + 备忘录

一般来说,让你在二维矩阵中求最优化问题(最大值或者最小值),肯定需要递归 + 备忘录,也就是动态规划。

image.png

我们想计算从起点 D 到达 B 的最小路径和,那你说怎么才能到达 B 呢?

题目说了只能向右或者向下走,所以只有从 A 或者 C 走到 B

怎么知道从 A 走到 B 才能使路径和最小,而不是从 C 走到 B 呢?

从 D 走到 A 的最小路径和是 6,而从 D 走到 C 的最小路径和是 8,6 小于 8,所以一定要从 A 走到 B 才能使路径和最小

换句话说,我们把「从 D 走到 B 的最小路径和」这个问题转化成了「从 D 走到 A 的最小路径和」和 「从 D 走到 C 的最小路径和」这两个问题。

这不就是状态转移方程吗?

dp 函数定义为:从左上角位置 (0, 0) 走到位置 (i, j) 的最小路径和为 dp(grid, i, j)

这样,dp(grid, i, j) 的值由 dp(grid, i - 1, j) 和 dp(grid, i, j - 1) 的值转移而来: dp(grid, i, j) = min( dp(grid, i-1, j), dp(grid, i, j-1), ) + grid[i][j]

var memo [][]int

func minPathSum(grid [][]int) int {
    m := len(grid)
    n := len(grid[0])
    // 构造备忘录,初始值全部设为 -1
    memo = make([][]int, m)
    for i := range memo {
        memo[i] = make([]int, n)
        for j := range memo[i] {
            memo[i][j] = -1
        }
    }

    return dp(grid, m-1, n-1)
}

func dp(grid [][]int, i, j int) int {
    // base case
    if i == 0 && j == 0 {
        return grid[0][0]
    }
    if i < 0 || j < 0 {
        return int(^uint(0) >> 1) // Integer.MAX_VALUE equivalent in Go
    }
    // 避免重复计算
    if memo[i][j] != -1 {
        return memo[i][j]
    }
    // 将计算结果记入备忘录
    memo[i][j] = min(
        dp(grid, i-1, j),
        dp(grid, i, j-1),
    ) + grid[i][j]

    return memo[i][j]
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}