一、需求
- 给定一个包含非负整数的
m x n
网格grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小; - 说明:每次只能向下或者向右移动一步。
输入:grid = [[1,3,1],[1,5,1],[4,2,1]] 输出:7 解释:因为路径 1→3→1→1→1 的总和最小。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 200
0 <= grid[i][j] <= 100
二、动态规划
2.1 思路分析
- 该题的思路可以完全照搬不同路径:https://blog.csdn.net/Sruggle/article/details/116008090;
- 本题是可以用滚动数组来优化空间复杂度的;
2.2 代码实现
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] f = new int[m][n];
//初始化第一列
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[i][j]
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];
}
}
2.3 复杂度分析
- 时间复杂度为O(mn),其中m、n为grid的行、列数;
- 空间复杂度为O(mn),dp数组消耗O(mn)的额外空间;
三、滚动数组
3.1 思路分析
- 在状态转移方程中发现状态f[i] [j]只与它之前的几个状态有关,该状态具有无后效性,因此可以使用滚动数组来优化;
- 所谓滚动数组可以想象一块电子屏幕,它要显示一长串数字,但是屏幕无法显示全部数字,只能滚动的显示一部分,即我们只需要屏幕这部分"空间"即可得到全部的数字,无须创造包含全部数字的"空间";比如斐波那契数列,正常的思路是初始化一个数组f[100],然后通过f[i] = f[i-1] + f[i]来确定每个位置的值,这其中消耗100个空间,实际上只要3个空间就可以实现;
- 在解法2中,首先计算了第一列、第一行,然后计算了其余行列。在这里只使用列数大小的空间,先计算第一行各个位置的最小路径和,在此基础上计算其余行各个位置的最小路径和,最后返回最后一行的最后一个位置对应的最小路径和即可。
3.2 代码实现(按列数分配空间)
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
//dp记录某一行各个位置的最小路径和
int[] dp = new int[n];
//初始化第一行
dp[0] = grid[0][0];
for(int j = 1; j < n; j++) {
dp[j] = dp[j - 1] + grid[0][j];
}
//初始化其余行
for(int i = 1; i < m; i++) {
dp[0] = dp[0] + grid[i][0];
for(int j = 1; j < n; j++) {
//这里的dp[j]表示前一行索引j处对应的最小路径和
dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j];
}
}
return dp[n - 1];
}
}
3.3 代码实现(按行数分配空间)
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
//dp记录某一列各个位置的最小路径和
int[] dp = new int[m];
//初始化第一列
dp[0] = grid[0][0];
for(int i = 1; i < m; i++) {
dp[i] = dp[i - 1] + grid[i][0];
}
//初始化其余列
for(int j = 1; j < n; j++) {
dp[0] = dp[0] + grid[0][j];
for(int i = 1; i < m; i++) {
//这里的dp[i]表示前一列索引i处对应的最小路径和
dp[i] = Math.min(dp[i], dp[i-1]) + grid[i][j];
}
}
return dp[m - 1];
}
}
3.4 复杂度分析
- 时间复杂度为O(mn);
- 空间复杂度为O(h),其中h为m或n;
四、学习地址
作者:MtTBbS3W8V