LeetCode - 64. 最小路径和

149 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


原题:64. 最小路径和

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

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

image.png

如上图,路径 1→3→1→1→1 的总和最小,因此最后的结果是 7

解题思路:

这是一个典型的动态规划题。因为每次只能向下或者向右移动一步,因此,从左上角开始,走到任何一个格子的做小路径和,都是「上方格子的最小路径和」与「左方格子的最小路径和」中较小的一个,加上当前格子本身的值。根据这个规律可以推导出状态转移方程:

定义一个与网格行列数相同的二维数组 dp[][],那么:

dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

除了以上的一般情况,还有几种情况需要考虑:

  • 当 i 和 j 都是 0 的时候,当前格子为左上角的个字,此时,dp[i][j] = grid[i][j]
  • 当 i 是 0,j 大于 0 的时候,dp[i][j] = dp[i][j-1] + grid[i][j]
  • 当 j 是 0,i 大于 0 的时候,dp[i][j] = dp[i-1][j] + grid[i][j]

从左上角到右下角依次按照以上的状态转移方程,dp 数组最右下角的元素既是结果。

另外,因为 dp 数组与题目参数 grid 数组大小相同,且过程中只需要左侧和上方格子的计算结果,因此可以直接在 grid 数组进行操作。

最终代码:

class Solution {
    public int minPathSum(int[][] grid) {
        int r = grid.length;
        if (r == 0) {
            return 0;
        }
        int c = grid[0].length;
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if (i == 0 && j == 0) {
                    continue;
                } else if (i == 0) {
                    grid[i][j] += grid[i][j - 1];
                } else if (j == 0) {
                    grid[i][j] += grid[i - 1][j];
                } else {
                    grid[i][j] += Math.min(grid[i][j - 1], grid[i - 1][j]);
                }
            }
        }
        return grid[r - 1][c - 1];
    }
}