LeetCode 64.最小路径和(中等)
原创
©著作权归作者所有:来自51CTO博客作者菜籽爱编程的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目描述
给定一个包含非负整数的 m x n
网格 grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2
输入:grid = [[1,2,3],[4,5,6]]
输出:12
提示
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 200
- 0 <= grid[i][j] <= 100
题目分析
这道题我们可以通过定义一个同样大小的矩阵 dp
来解决,其中的 dp[i][j]
表示的是从左上角开始到 (i, j)
位置的最优路径的累计值。因为每次只能向下或者向右移动,所以状态转移方程为 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
,特别注意边界情况即可。(见题解一)累加的方法类似于 LeetCode 304. 二维区域和检索 - 矩阵不可变
。当然,我们还能对空间进行压缩,因为 dp
矩阵的每一个值只和左边和上面的值相关,我们可以使用空间压缩将 dp
数组压缩为一维。对于第 i
行,在遍历到第 j
列的时候,因为第 j-1
列已经更新过了,所以 dp[j-1]
代表 dp[i][j-1]
的值;而 dp[j]
待更新,当前存储的值是在第 i-1
行的时候计算的,所以代表 dp[i-1][j]
的值。(见题解二)
题解一
执行用时: 2 ms
内存消耗: 44.3 MB
class Solution {
public int minPathSum(int[][] grid) {
// 获取矩阵大小
int m = grid.length;
int n = grid[0].length;
// 定义 dp 矩阵
int[][] dp = new int[m][n];
// 遍历原矩阵
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
// 当遍历到第一个位置时
// 路径累计值等于该位置路径值
if (i == 0 && j == 0) {
dp[i][j] = grid[i][j];
} else if (i == 0) {
// i = 0 的边界情况
// 路径只能从 j - 1 通过
dp[i][j] = dp[i][j - 1] + grid[i][j];
} else if (j == 0) {
// j = 0 的边界情况
// 路径只能从 i - 1 通过
dp[i][j] = dp[i - 1][j] + grid[i][j];
} else {
// 普通情况取左边或上边累加的最小值加上当前位置的路径值
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
}
return dp[m - 1][n - 1];
}
}
题解二
执行用时: 2 ms
内存消耗: 43.8 MB
class Solution {
public int minPathSum(int[][] grid) {
// 获取矩阵大小
int m = grid.length;
int n = grid[0].length;
// 定义 dp 数组
int[] dp = new int[n];
// 遍历原矩阵
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
// 当遍历到第一个位置时
// 路径累计值等于该位置路径值
if (i == 0 && j == 0) {
dp[j] = grid[i][j];
} else if (i == 0) {
// i = 0 的边界情况
dp[j] = dp[j - 1] + grid[i][j];
} else if (j == 0) {
// j = 0 的边界情况
dp[j] = dp[j] + grid[i][j];
} else {
// 普通情况取左边或上边累加的最小值加上当前位置的路径值
dp[j] = Math.min(dp[j], dp[j - 1]) + grid[i][j];
}
}
}
return dp[n - 1];
}
}
题目来源:力扣(LeetCode)