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.
思路1:
最简单的方法就是利用动态规划,开辟一个新的m x n数组,该数组的每个元素保存的都是从top left到当前元素的最小和。详细步骤:
1)最左侧元素设为当前元素和上面元素的和;
2)最顶端元素设为当前元素和左边元素的和;
3)剩下的元素为该元素位置上min(上面的元素,左边的元素)加上当前元素的和;
4)返回dp[row-1][col-1]即可。
Note:
该方法的空间复杂度为O(m*n),时间复杂度为O(n)。
思路2:
依然使用动态规划,但在代码实现中使用一种技巧来减少占用的空间。
设置状态为flag[i][j]表示到达网格(i,j)的总和的最小的路径的值,则状态转移方程为:
flag[i][j] = min(flag[i-1][j], flag[i][j-1]) + grid[i][j]
在代码实现过程中,用一维数组dp[j]表示外循环第i次迭代内循环第j次迭代对应的sum值。在还没更新状态时,dp[j]对应flag[i-1][j]; dp[j-1]对应flag[i][j-1]。
该方法的空间复杂度为O(n),时间复杂度为O(n)。
思路3:
采用递归策略,从右下角终点开始向前递归,也是利用了问题的最优解包含子问题的最优解这一思想,层层递归,直到起点。
该方法的主要缺点是时间复杂度比较大,对于如下数组,在leetcode中会返回Time Limit Exceeded错误。
[[7,1,3,5,8,9,9,2,1,9,0,8,3,1,6,6,9,5],[9,5,9,4,0,4,8,8,9,5,7,3,6,6,6,9,1,6],[8,2,9,1,3,1,9,7,2,5,3,1,2,4,8,2,8,8],[6,7,9,8,4,8,3,0,4,0,9,6,6,0,0,5,1,4],[7,1,3,1,8,8,3,1,2,1,5,0,2,1,9,1,1,4],[9,5,4,3,5,6,1,3,6,4,9,7,0,8,0,3,9,9],[1,4,2,5,8,7,7,0,0,7,1,2,1,2,7,7,7,4],[3,9,7,9,5,8,9,5,6,9,8,8,0,1,4,2,8,2],[1,5,2,2,2,5,6,3,9,3,1,7,9,6,8,6,8,3],[5,7,8,3,8,8,3,9,9,8,1,9,2,5,4,7,7,7],[2,3,2,4,8,5,1,7,2,9,5,2,4,2,9,2,8,7],[0,1,6,1,1,0,0,6,5,4,3,4,3,7,9,6,1,9]]
思路1代码实现:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
vector<vector<int>> dp = grid;
int row = grid.size(), col = grid[0].size();
for(int i = 1; i < row; ++i)
dp[i][0] += dp[i-1][0];
for(int j = 1; j < col; ++j)
dp[0][j] += dp[0][j-1];
for(int i = 1; i < row; ++i)
for(int j = 1; j < col; ++j)
dp[i][j] += min(dp[i-1][j], dp[i][j-1]);
return dp[row-1][col-1];
}
};思路2代码实现:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int row = grid.size(), col = grid[0].size();
vector<int> dp = grid[0];
for (unsigned int j = 1; j < col; j++)
dp[j] += dp[j-1];
for (unsigned int i = 1; i < row; i++)
{
dp[0] += grid[i][0];
for (unsigned int j = 1; j < col; j++)
dp[j] = grid[i][j] + min(dp[j-1], dp[j]);
}
return dp[col-1];
}
};思路3代码实现:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int row = grid.size(), col = grid[0].size();
return path_proxy(grid, row-1, col-1);
}
private:
int path_proxy(vector<vector<int>>&grid, int i, int j)
{
if(i == 0 && j == 0) return grid[0][0];
if(i == 0 && j != 0)
{
int result = grid[0][0];
for(int k = 1; k <= j; ++k)
result += grid[0][k];
return result;
}
if(i != 0 && j == 0)
{
int result = grid[0][0];
for(int k = 1; k <= i; ++k)
result += grid[k][0];
return result;
}
return min(path_proxy(grid, i-1, j), path_proxy(grid, i, j-1)) + grid[i][j];
}
};
本文介绍了一种算法问题,即寻找从网格左上角到右下角路径上的最小数字之和,仅允许向右或向下移动。通过三种方法解决此问题:动态规划(两种不同实现)及递归策略。

362

被折叠的 条评论
为什么被折叠?



