最小路径和
题目描述
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7解释: 因为路径 1→3→1→1→1 的总和最小。
排除掉m和n中有一个为0的情况,我们进行分类讨论。
当m为0时,靠边上那一排单纯点往右边走,计算出每位选手的最小和
当n为0时,靠边上那一列单纯点往下走,计算出每位选手的最小和
排除楼上两种情况后,考虑中间任意点的最小和等于其自身加上和其自身相邻的左边那位或者上边那位的最小和的最小值
最后,我们只要返回最后那个元素的最小和就好了。
用Javascript语言的相关实现如下:
var minPathSum = function (grid) {
var row = grid.length;
if (!row) return 0;
var col = grid[row - 1].length;
if (!col) return 0;
var dp = [...grid];
for (var i = 1; i < row; i++) {
dp[i][0] = grid[i - 1][0] + grid[i][0];
}
for (var i = 1; i < col; i++) {
dp[0][i] = grid[0][i - 1] + grid[0][i];
}
for(var i = 1; i < row; i++) {
for (var j = 1; j < col; j++) {
dp[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
}
}
return dp[row - 1][col - 1];
};
这里提及一下,在JS中数组是引用类型的,所以你要用深拷贝来解决数组拷贝问题。
解法二:(C++)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size();
vector<int> dp(n, INT_MAX);
dp[0] = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (j == 0) dp[j] += grid[i][j];
else dp[j] = grid[i][j] + min(dp[j], dp[j - 1]);
}
}
return dp[n - 1];
}
};
解法三:(C++)
我们还可以进一步的优化空间,连一维数组都不用新建,而是直接使用原数组 grid 进行累加,这里的累加方式跟解法一稍有不同,没有提前对第一行和第一列进行赋值,而是放在一起判断了,当i和j同时为0时,直接跳过。否则当i等于0时,只加上左边的值,当j等于0时,只加上面的值,否则就比较左边和上面的值,加上较小的那个即可,参见代码如下:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[i].size(); ++j) {
if (i == 0 && j == 0) continue;
if (i == 0) grid[0][j] += grid[0][j - 1];
else if (j == 0) grid[i][0] += grid[i - 1][0];
else grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]);
}
}
return grid.back().back();
}
};
解法四:(C++)
下面这种写法跟上面的基本相同,只不过用了 up 和 left 两个变量来计算上面和左边的值,看起来稍稍简洁一点,参见代码如下:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[i].size(); ++j) {
if (i == 0 && j == 0) continue;
int up = (i == 0) ? INT_MAX : grid[i - 1][j];
int left = (j == 0) ? INT_MAX : grid[i][j - 1];
grid[i][j] += min(up, left);
}
}
return grid.back().back();
}
};