46.最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
思路1分析:
**注意:**先把第0行和第0列进行初始化(第一行只能从左一直往右走,而第一列只能从上一直往下走,并且将经过的点累加起来形成累积的路径和。)
状态转移方程为dp[i][j] = min { dp[i - 1] [j], dp[i] [j - 1] } + m[i] [j]。可以用一个二维的 dp 矩阵来求解。对于 dp 矩阵,第一行和第一列只会有一种走法,就是从左到右或者从上到下的累加,所以可以先进行初始化,然后其他元素就可以用过转移方程一个一个填充。
边界条件
if(m == null || m.length == 0 || m[0] == null || m[0].length == 0)
参考网友的代码:
class Solution {
public int minPathSum(int[][] grid) {
//动态规划
if(grid == null || grid.length == 0){
return 0;
}
int m = grid.length;
int n = grid[0].length;
//用来记录当前节点到左上角的最短路径
int [][]dp = new int[m][n];
dp[0][0] = grid[0][0];
//因为第一行每次只能向下,所以第一列只能是往下走得到每个位置的累计路径和
for(int j = 1; j < m; j++){
dp[j][0] = dp[j-1][0] + grid[j][0];
}
//第一行只能从左一直往右走
for(int i = 1; i < n; i++){
dp[0][i] = dp[0][i-1] + grid[0][i];
}
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];
}
}
思路2分析
优化:使用一个一维数组进行这个迭代过程
上面的动态规划代码,时间复杂度是O(MN),空间复杂度就是二维数组的大小O(MN)。
空间压缩的方法是不用记录所有的子问题的解。
所以就可以只用一个行数组记录第一行、第二行…依次计算……………直到最后一行,得到 dp[N-1] 就是左上角到右下角的最小路径和。
优化后的代码:
class Solution {
public int minPathSum(int[][] grid) {
if(grid == null)
return 0;
int row = grid.length;
int col = grid[0].length;
int[] dp = new int[col];
dp[0] = grid[0][0];
//计算第一行的最短路径
for(int j=1;j<col;j++){
dp[j] = dp[j-1] + grid[0][j];
}
//计算除了第一行的其他最小路径和
for(int i=1;i<row;i++){
//dp[0]代表每一行最左边的dp,后一行的dp覆盖前一行的dp
dp[0] = dp[0] + grid[i][0];
for(int j=1;j<col;j++){
//后面的dp[j]保存的是这行这个位置的上一行位置,表示从上往下的方向
//dp[j-1]表示从左往右的方向
dp[j] = Math.min(dp[j-1],dp[j]) + grid[i][j];
}
}
return dp[col-1];
}
}
参考:https://blog.csdn.net/u013309870/article/details/69569456