携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>\
一、题目描述
给定一个 m*n 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上左右数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围:1<=n,m<=500,矩阵中任意值都满足 0<= nums <= 100
要求:时间复杂度O(nm)
输入: grid = [[1,3,1],[1,5,1],[4,2,1]]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
二、思路分析
1.本题为经典的二维动态规划题目。
2.使用动态规划思想时,考虑如何将问题进行合理拆分,使其变为由一个一个子问题组,通过求解子问题从而解决最后的问题。本题需要求解从左上走到右下(grid[0][0]→grid[n-1][m-1])所需的最小路径和,可以考虑走到grid[n-1][m-2]和grid[n-2][m-1]时哪个路径最短,以此类推。。。
3.在划分子问题时可以分为三种情况:
(1)网格的第一行的每个元素只能从左上角元素开始向右移动到达
(2)网格的第一列的每个元素只能从左上角元素开始向下移动到达
(3)对于不在第一行和第一列的元素,可以从其上方相邻元素向下移动一步到达,或者从其左方相邻元素向右移动一步到达
所以状态转移方程也分为3个:
(1)dp[0][i] = dp[0][i-1] + grid[0][i]
(2)dp[j][0] = dp[j-1][0] + grid[j][0]
(3)dp[i][j] = Math.min(dp[i-1][j] + grid[i][j], dp[i][j-1] + grid[i][j])
三、代码
class App{
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0){
return 0;
}
int row = grid.length;
int col = grid[0].length;
int[][] dp = new int[row][col];
dp[0][0] = grid[0][0];
for (int i=1; i<row; i++){
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for (int j=1; j<col; j++){
dp[0][j] = dp[0][j-1] + grid[0][j];
}
for (int i=1; i<row; i++){
for (int j=0; j<col; j++){
dp[i][j] = Math.min(dp[i-1][j] + grid[i][j], dp[i][j-1] + grid[i][j]);
}
}
return dp[row-1][col-1];
}
}
四、总结
本题使用动态规划思想,建立二维动态规划数组,将每走到一个格子的最短路径值存储到数组的相应位置,最后只需得到数组右下角格子的值就可以得到问题的最终解。其时间复杂度为O(nm),空间复杂度为O(nm)。