Leetcode 064 最小路径和 C++ Python

题目:

给定一个包含非负整数的 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;
};

猜你喜欢

转载自blog.csdn.net/weixin_41958153/article/details/81317407