LeetCode64. 最小路径和

思路: 参考左神P187

  1. 状态的定义:dp[i][j]表示从左上角即(0,0)位置走到(i,j)位置的最小路径和。

  2. 特殊情况: 对于矩阵第一行的所有位置,从(0,0)走到(0,j)只能一直往右走。同理, 对于矩阵第一列的所有位置,从(0,0)走到(i,0)只能一直往下走。

  3. 除了第一行和第一列,从(0,0)位置走到(i,j)位置的路径必然经过位置(i-1,j) 或 位置(i,j-1),所以dp方程为 dp[i][j] = min{dp(i-1,j) , dp(i,j-1)} + m[i][j]

   即,除第一行和第一列之外,每个位置都考虑从左边到达自己的路径和更小还是从上边到达自己的路径和更小。最右下角的值就是答案。

☆☆☆☆方法1:经典DP。 时间复杂度为O(M*N), 空间复杂度为O(M*N)

☆☆☆☆☆方法2:DP+空间压缩,不使用大小为M*N的dp数组,而仅仅使用大小为min{M, N}的数组。   时间复杂度为O(M*N), 空间复杂度为O(min{M, N})

       根据给定矩阵行和列的大小关系决定滚动方式,始终生成最小长度min{M, N}的arr数组

        如果M > N, 滚动更新arr数组,让arr依次变成dp矩阵每一行的值。最终变成dp矩阵最后一行的值。

        如果M<N, 则令arr更新成dp矩阵每一列的值,从左向右滚动过去。

        如果M=N,按行 更新 和 按列 更新均可。

代码1:

class Solution {
    public int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
            return 0;
        }
        int m = grid.length, n = grid[0].length;
        // 1. 状态定义:从(0,0)到(i,j)的最小路径和
        int[][] dp = new int[m][n];
        // 第一行
        dp[0][0] = grid[0][0]; // 2. 初始化
        for (int j = 1; j < n; j++) {
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        // 第一列
        for (int i = 1; i < m; i++) {
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                // 3.dp方程
                dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}

代码2(空间压缩):

class Solution {
    public int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
            return 0;
        }
        int more = Math.max(grid.length, grid[0].length); // 行数与列数较大的那个为more
        int less = Math.min(grid.length, grid[0].length); // 行数与列数较小的那个为less
        boolean rowmore = more == grid.length;  // 行数是不是 大于等于列数
        int[] arr = new int[less]; // arr数组的长度取决于行数和列数的较小值
        // 初始化
        arr[0] = grid[0][0];
        for (int i = 1; i < less; i++) {
            arr[i] = arr[i-1] + (rowmore ? grid[0][i] : grid[i][0]);
        }
        
        for (int i = 1; i < more; i++) {
            arr[0] = arr[0] + (rowmore ? grid[i][0] : grid[0][i]);
            for (int j = 1; j < less; j++) {
                arr[j] = Math.min(arr[j-1], arr[j]) + (rowmore ? grid[i][j] : grid[j][i]);
            }
        }
        return arr[less - 1];
    }
}
原文地址:https://www.cnblogs.com/HuangYJ/p/14213731.html