Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
思路:
典型的动态规划问题。
设dp[i][j]表示从左上角到grid[i][j]的最小路径和。那么dp[i][j] = grid[i][j] + min( dp[i-1][j], dp[i][j-1] );
下面的代码中,为了处理计算第一行和第一列的边界条件,我们令dp[i][j]表示从左上角到grid[i-1][j-1]的最小路径和,最后dp[m][n]是我们所求的结果。
复杂度:O(mn)
Attention:
1. 初始化vector容器时,需要将初值设为INT_MAX,因为后面要比较较小值。
vector<vector<int>>dp(row+1, vector<int>(col+1, INT_MAX));
2. 需要初始化dp[0][1]的值,动态规划需要设定初值。
3. 注意规划的迭代公式,dp存储了一个可走路径的表。
dp[m][n] is a matrix store the min value of every location we can get.
边界处理,dp[i][j]表示从左上角到grid[i-1][j-1]的最小路径和。
dp[ri][ci] = grid[ri-1][ci-1] + min(dp[ri-1][ci], dp[ri][ci-1]);
AC Code:
class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
if(grid.empty() || grid[0].empty()) return 0;
int row = grid.size();
int col = grid[0].size();
//初始化为INT_MAX,因为后面要取最小值
vector<vector<int>>dp(row+1, vector<int>(col+1, INT_MAX));
//dp[0][1]需初始化才能开始
dp[0][1] = 0;
for(int ri = 1; ri <= row; ri++)
{
for(int ci = 1; ci <= col; ci++)
{
dp[ri][ci] = grid[ri-1][ci-1] + min(dp[ri-1][ci], dp[ri][ci-1]);
}
}
return dp[row][col];
}
};
优化算法:空间复杂度降低到O(min(row, col))
思路:dp[i][j] 只和上一行的dp[i-1][j]和上一列的dp[i][j-1]有关,dp[i][j]是一行一行计算的(根据循环),dp[j-1]表示前一列的值(已经更新为本行的前一列的值),dp[j]保存了上一行的值(dp的值逐行更新,始终存储着一行的值,使用时即对应上一行的值(还没有更新))。基于这个原理,我们不需要存储所有的列的值。可以将空间复杂度降到O(min(row, col))
Attention:
1. 最后取值时,取vector容器的最后的数 。dp.back();
2. 初始化dp[1] = 0; 循环开始dp[1] = grid[0][0] + min(dp[1], dp[0]); <=> dp[1] = grid[0][0] + min(0, INT_MAX);
AC Code:
class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
if(grid.empty() || grid[0].empty()) return 0;
int row = grid.size();
int col = grid[0].size();
vector<int> dp(col+1, INT_MAX);
dp[1] = 0;
for(int ri = 1; ri <= row; ri++)
{
for(int ci = 1; ci <= col; ci++)
{
dp[ci] = grid[ri-1][ci-1] + min(dp[ci], dp[ci-1]);
}
}
return dp.back();
}
};