法1:动态规划(未优化版)
想法:
- 对于第 i 行、第 j 列位置,从左上角到此位置的最小路径为:
dp[i][j] = grid[i][j] + min{dp[i - 1][j] , dp[i][j - 1]}
dp[i - 1][j] 表示从上走到下到达[i][j];dp[i][j - 1]表示从左走到右到达[i][j]
/**
* @param {number[][]} grid
* @return {number}
*/
var minPathSum = function(grid) {
var dp = [], temp = [];
var i = 0, j = 0, m = grid.length, n = grid[0].length;
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
temp[j] = 0;
}
dp[i] = temp;
temp = [];
}
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
if(i - 1 >= 0 && j - 1 >= 0) {
dp[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
continue;
}
if(i - 1 >= 0 && j - 1 < 0) {
dp[i][j] = grid[i][j] + dp[i - 1][j];
continue;
}
if(i - 1 < 0 && j - 1 >= 0) {
dp[i][j] = grid[i][j] + dp[i][j - 1];
continue;
}
dp[i][j] = grid[i][j];
}
}
return dp[m - 1][n - 1];
};
法2:动态规划(优化)
看了题解,参考做了一些优化。
想法:
- 右下角的列坐标必定等于grid的最大列坐标
- 行坐标作为外循环,列坐标作为内循环;则经过一轮内循环后,列坐标与右下角列坐标相等,若此时行坐标与右下角行坐标相等,则自动退出循环
- 则:实际上只需要一个一维数组,来保存每行的最短路径情况。即dp[],长度为grid[0].length。假设已经访问了第一行,访问到第二行时,如第j位置时,可选择min{dp[j - 1], dp[j]};此时dp[j - 1]是已经更新的到达第2行第j - 1列的最短路径(当前要达到位置的左方),dp[j]是尚未更新的到达第1行第j列的最短路径(当前要到达位置的上方)。这样dp中保存的是:左上角到达最新一行中每个位置的最短路径。
/**
* @param {number[][]} grid
* @return {number}
*/
var minPathSum = function(grid) {
var dp = [];
var i = 0, j = 0, m = grid.length, n = grid[0].length;
for(j = 0; j < n; j++) {
dp[j] = 0;
}
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
if(j == 0) { // 在第一列,只能从上边来
dp[j] = dp[j];
}
else if(i == 0) { // 在第一行,只能从左边来
dp[j] = dp[j - 1];
}
else {
dp[j] = Math.min(dp[j - 1], dp[j]);
}
dp[j] = dp[j] + grid[i][j];
}
}
return dp[n - 1];
};