64. 最小路径和

375 阅读2分钟

题目介绍

力扣64题:leetcode-cn.com/problems/mi…

image.png

方法:动态规划

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

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

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

i > 0j = 0 时,dp[i][0] = dp[i−1][0] + grid[i][0]

i = 0j > 0 时, dp[0][j] = dp[0][j−1] + grid[0][j]

i > 0 j > 0 时,dp[i][j]=Math.min(dp[i−1][j],dp[i][j−1]) + grid[i][j]

image.png

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

代码如下:

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        //初始化第一列的值,由于第一列只能向下,所以只能向下相加
        for(int i = 1; i < m; i++) {
            dp[i][0] = grid[i][0] + dp[i-1][0];
        }

        //初始化第一行的值,由于第一行只能向右,所以只能向右相加
        for(int i = 1; i < n; i++) {
            dp[0][i] = grid[0][i] + dp[0][i-1];
        }

        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}

复杂度分析

  • 时间复杂度:O(mn),其中 mn 分别是网格的行数和列数。需要对整个网格遍历一次,计算 dp 的每个元素的值。

  • 空间复杂度:O(mn),其中 mn 分别是网格的行数和列数。创建一个二维数组 dp,和网格大小相同。空间复杂度可以优化,例如每次只存储上一行的 dp 值,则可以将空间复杂度优化到 O(n)