题目:
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。
算法过程:
利用动态规划的思路
dp[i][j]用来表示到达这个点所需要的最小和,它等于这个位置上的值+min(dp[i-1][j], dp[i][j-1])。
无需证明
代码:
Python:
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m = len(grid)
if m == 0:
return 0
n = len(grid[0])
#动态规划的思路
dp = [[0 for _ in range(n)] for _ in range(m)]
dp[0][0] = grid[0][0]
#第0列的所有都等于上一项加自己这项
for i in range(1, m):
dp[i][0] = dp[i-1][0] + grid[i][0]
for i in range(1, n):
dp[0][i] = dp[0][i-1] + grid[0][i]
#权衡一下,取左边或者是上边的最小值,毕竟我们要确定的是到[i][j]这个位置的最小和。
for i in range(1, m):
for j in range(1, n):
dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
return dp[m-1][n-1]
C++
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(grid.size() == 0)
return 0;
int m = grid.size();
int n = grid[0].size();
m_memo = vector<vector<int>>(m+1,vector<int>(n+1,0));
//初始化边界情况
for(int i = n-1; i >= 0;--i)
m_memo[m-1][i] = grid[m-1][i] + m_memo[m-1][i+1];
for(int j = m-1; j >= 0;--j)
m_memo[j][n-1] = grid[j][n-1] + m_memo[j+1][n-1];
for(int i = m-2; i >= 0;--i)
{
for(int j = n-2; j >= 0;--j)
{
m_memo[i][j] = grid[i][j] + min(m_memo[i][j+1], m_memo[i+1][j]);
}
}
return m_memo[0][0];
}
};
但是在搜索网上答案的时候,看到了另一种精彩的解法:
为什么大家做动态规划的时候都喜欢从下至上呢?可能就是因为递归是一种从上至下的思考方式,而动态规划去思考的时候就容易产生这种逆向思维。
所以接下来要贴的是C++的递归解法:
但是我读了代码之后比较一头雾水,为什么要这样大费周章地去使用递归。。。
大家觉得这代码怎么样呢。。
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(grid.size() == 0)
return 0;
int m = grid.size();
int n = grid[0].size();
m_memo = vector<vector<int>>(m+1,vector<int>(n+1,0));
//初始化边界情况
for(int i = n-1; i >= 0;--i)
m_memo[m-1][i] = grid[m-1][i] + m_memo[m-1][i+1];
for(int j = m-1; j >= 0;--j)
m_memo[j][n-1] = grid[j][n-1] + m_memo[j+1][n-1];
return minPathSumRecusion(grid, 0, 0);
}
private:
//封装在private里的递归方法
int minPathSumRecusion(vector<vector<int>>& grid, int m, int n){
if(grid.size() == 0)
return 0;
if(m_memo[m][n] != 0)
{
return m_memo[m][n];
}
if(m == grid.size()-1 && n == grid[0].size()-1)
{
m_memo[m][n] = grid[m][n];
return m_memo[m][n];
}
if(m == grid.size()-1)
{
return m_memo[m][n];
}
if(n == grid[0].size()-1)
{
return m_memo[m][n];
}
//但是我实在不敢恭维这种思路,循环能做的事为什么用递归去做?
m_memo[m][n] = min(grid[m][n]+minPathSumRecusion(grid,m+1,n), grid[m][n]+minPathSumRecusion(grid,m,n+1));
return m_memo[m][n];
}
vector<vector<int>> m_memo;
};