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

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

测试用例

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

解题思路

动态规划
由于路径的方向只能是向下或向右,因此网格的第一行的每个元素只能从左上角元素开始向右移动到达,网格的第一列的每个元素只能从左上角元素开始向下移动到达,此时的路径是唯一的,因此每个元素对应的最小路径和即为对应的路径上的数字总和。

对于不在第一行和第一列的元素,可以从其上方相邻元素向下移动一步到达,或者从其左方相邻元素向右移动一步到达,元素对应的最小路径和等于其上方相邻元素与其左方相邻元素两者对应的最小路径和中的最小值加上当前元素的值。
由于每个元素对应的最小路径和与其相邻元素对应的最小路径和有关,因此可以使用动态规划求解。

创建二维数组dp,与原始网格的大小相同,dp[i][j] 表示从左上角出发到 (i,j) 位置的最小路径和。显然,dp[0][0]=grid[0][0]。对于dp中的其余元素,通过以下状态转移方程计算元素值。

  • 当i > 0且j = 0时,dp[i][0] = dp[i − 1][0] + grid[i][0]。(第一行)
  • 当i = 0且j > 0时,dp[0][j] = dp[0][j - 1] + grid[0][j]。(第一列)
  • 当i > 0且j > 0时,dp[i][j]=min(dp[i − 1][j], dp[i][j − 1]) + grid[i][j]。

最后得到 dp[m - 1][n − 1] 的值即为从网格左上角到网格右下角的最小路径和。

Code

class Solution {
    public int minPathSum(int[][] grid) {
        if (grid == null){
            return 0;
        }

        int m = grid.length;
        int n = grid[0].length;
        int[][] f = new int[m][n];

        //f状态初始化
        f[0][0] = grid[0][0];
        for(int i = 1; i < m; i++) {
            f[i][0] = f[i - 1][0] + grid[i][0];
        }
        for(int j = 1; j < n; j++) {
            f[0][j] = f[0][j - 1] + grid[0][j];
        }

        //f状态转移
        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + grid[i][j];
            }
        }
        return f[m- 1][n- 1];

    }
}

原文链接:https://blog.csdn.net/weixin_43405220/article/details/107643258

最后修改日期:2020年7月29日