题号 64
题目描述
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
解题思路——动态规划
本题是 leetcode #62、#63 的升级版,不是算最多路径数,而是算所有路径中代价最小的那条路径。
关于 题62、题63 的解决方案可以参考下方链接:
leetcode #62 不同路径 | 刷题之路第二站——动态规划类问题
leetcode #63 不同路径 II | 刷题之路第二站——动态规划类问题
Step1:描述问题的最优解结构特征
问题等价于求从起点 S[ 0 ][ 0 ] 到终点 S[ m - 1][ n - 1 ] 的所有路径中代价最小的那条路径。
直接通往 S[ m - 1 ][ n - 1] 有两种方式:
1- 由 S[ m - 2 ][ n - 1] 向下移动一格到达;
2- 由 S[ m - 1][ n - 2] 向右移动一个到达;
如果我们知道从 S[ 0 ][ 0 ] 到 S[ m - 2][ n -1 ] 的代价最小的路径和从S[ 0 ][ 0 ] 到 S[ m - 1 ][ n - 2 ] 的代价最小的路径,取二者中较小的一个,将其与 S[ m - 1 ][ n - 1 ] 相加,即为从起点 S[ 0 ][ 0 ] 到终点 S[ m - 1][ n - 1 ] 的所有路径中代价最小的路径。
此问题的底为:
1- S[ 0 ][ 0 ]
2- 对于第一行的其他元素而言,从 S[ 0 ][ 0 ] 到 S[ 0 ][ i ] 的最小路径为从 S[ 0 ][ 0 ] 到 S[ 0 ][ i - 1 ] 的最小路径加上 S[ 0 ][ i ] 的值;
3- 对于第一列的其他元素而言,从 S[ 0 ][ 0 ] 到 S[ i ][ 0 ] 的最小路径为从 S[ 0 ][ 0 ] 到 S[ i - 1 ][ 0 ] 的最小路径加上 S[ i ][ 0 ]的值。
Step2:递归定义最优解值
令 p( i, j ) 为 从起点 S[ 0 ][ 0 ] 到达点 S[ i ][ j ] 的最小路径的数字之和。
首先,p[ 0 ][ 0 ] = S[ 0 ][ 0 ];
其次,p[ i ][ j ] = S[ i ][ j ] + min(p[ i ][ j - 1 ], p[ i - 1 ][ j ])。
Step3、4:自底向上计算最优解值、输出最优解值
问题的解就是终点 p[ m - 1 ][ n - 1 ] 的值。
代码实现如下:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.size() == 0 || grid[0].size() == 0)
return 0;
int m, n;
m = grid.size();
n = grid[0].size();
vector<vector<long>> p(m, vector<long>(n)); //使用二维数组p存放到每个元素的最小路径的数字之和
p[0][0] = grid[0][0]; //底
for (int i = 1; i < n; i++) {
p[0][i] = grid[0][i] + p[0][i - 1];
}
for (int i = 1; i < m; i++) {
p[i][0] = grid[i][0] + p[i - 1][0];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
p[i][j] = grid[i][j] + min(p[i][j - 1], p[i - 1][j]);
}
}
return p[m - 1][n - 1];
}
};
时间复杂度:O( m × n )
空间复杂度:O( m × n )