64. MinimumPath Sum – 动态规划
Given a m x n grid filled withnon-negative numbers, find a path from top left to bottom right which minimizes thesum of all numbers along its path.
Note: You can only move either down orright at any point in time.
Example:
Input:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes thesum.
思路:
我一开始的思路就是dfs,直接遍历所有情况,但实际超时了。
void dfs(const vector<vector<int> >& grid, int i, int j, int cur_sum, int& min_sum)
{
cur_sum += grid[i][j];
int m = grid.size(), n = grid[0].size();
if(i == m - 1 && j == n - 1)
{
min_sum = min(min_sum, cur_sum);
return;
}
if(i < m - 1)
dfs(grid, i + 1, j, cur_sum, min_sum);
if(j < n - 1)
dfs(grid, i, j + 1, cur_sum, min_sum);
}
int minPathSum(vector<vector<int>>& grid)
{
if(grid.size() == 1)
return accumulate(grid[0].begin(), grid[0].end(), 0);
int min_sum = 9999999;
dfs(grid, 0, 0, 0, min_sum);
return min_sum;
}
正确思路:
这是一个典型的DP问题,计算到grid[i][j]点的最短距离,state equation 是 S[i][j] = min(S[i - 1][j], S[i][j - 1]) + grid[i][j]。
先计算第一行第一列的所有值,然后从左上到右下一个一个计算,这样很容易得到代码。
int minPathSum(vector<vector<int>>& grid)
{
int m = grid.size();
int n = grid[0].size();
vector<vector<int> > sum(m, vector<int>(n, grid[0][0]));
for (int i = 1; i < m; i++)
sum[i][0] = sum[i - 1][0] + grid[i][0];
for (int j = 1; j < n; j++)
sum[0][j] = sum[0][j - 1] + grid[0][j];
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
sum[i][j] = min(sum[i - 1][j], sum[i][j - 1]) + grid[i][j];
return sum[m - 1][n - 1];
}
优化之后可以得到空间复杂度只有一个vector大小的代码。相当于按列,从最左边到最右边,每列从上至下,判断从[0][0]点,到每一个点的最短路径(不记录路径,只记录路径长度)。其中,cur_path表示的是当前这列,第i行的这个位置的数的path,所以是这个位置上方,以及左侧两个位置的值中较小值加上自身的值。
int minPathSum(vector<vector<int>>& grid)
{
int m = grid.size();
int n = grid[0].size();
vector<int> cur_path(m, 0);
cur_path[0] = grid[0][0];
for(int i = 1; i < m; i++)
cur_path[i] = cur_path[i - 1] + grid[i][0];
for(int j = 1; j < n; j++)
{
cur_path[0] += grid[0][j];
for(int i = 1; i < m; i++)
cur_path[i] = min(cur_path[i - 1], cur_path[i]) + grid[i][j];
}
return cur_path[m - 1];
}