zoukankan      html  css  js  c++  java
  • LeetCode-64. 最小路径和

    题目描述

    给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

    说明:每次只能向下或者向右移动一步。

    示例:

    输入:
    [[1,3,1],
    [1,5,1],
    [4,2,1]
    ]
    输出: 7
    解释: 因为路径 1→3→1→1→1 的总和最小。

    思路

    以输入为 3*3 的网格为例,其中 m=3,n=3
    [1,3,1]
    [1,5,1]
    [4,2,1]
    由于每次只能向下或者向右移动,则坐标(0,0)的最小路径就等于当前节点加上(0,1)或(1,0)的最小值,这样可以得到递归方程:
    dp(0,0) = grid(0,0) + min(dp(1,0),dp(0,1))
    当到达网格的边界时,下一步只能往右走或者往下走。这样可以得到这个问题的一般递归解法。

    一般递归解法

    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            return minPathSumRecusion(grid, 0, 0);
        }
    private:
        int minPathSumRecusion(vector<vector<int>>& grid, int m, int n){
            if(grid.size() == 0)
                return 0;
            
            if(m == grid.size()-1 && n == grid[0].size()-1)
                return grid[m][n];
            
            if(m == grid.size()-1)
                return grid[m][n]+minPathSumRecusion(grid,m,n+1);
            
            if(n == grid[0].size()-1)
                return grid[m][n]+minPathSumRecusion(grid,m+1,n);
    
            return grid[m][n]+ min(minPathSumRecusion(grid,m+1,n), minPathSumRecusion(grid,m,n+1));
        }
    };
    

    在leetcode上提交之后,不出意外的又超时了。下面先进行记忆化搜索进行优化,再进行动态规划算法的改写。

    记忆化搜索递归

    在得到一般递归解法后进行记忆化搜索的步骤一般比较固定,先建立每一步的索引表,然后初始化边界情况,然后在递归函数中判断索引表中的数据是否存在,如果存在则直接取出作为本次递归的值,不存在则继续进行下一步递归,递归返回时填写索引表中的相应值。
    这个问题比较特殊的地方在于边界情况有稍许复杂:

    • grid为0的情况
    • 下一步只能往右的情况
    • 下一步只能往下的情况
    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:
        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;
    };
    

    动态规划

    按照上面的递归公式和记忆化搜索算法,如果把递归算法从(0,0)逐步递归得到(m,n)看作是自顶向下,那么从(m,n)开始通过循环逐步得到(0,0)就可以看作是自底向上,我们可以进一步得出此题的动态规划解法。

    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];
        }
    };
    
  • 相关阅读:
    【struts2】【2】添加interceptor出错
    C++本质:类的赋值运算符=的重载,以及深拷贝和浅拷贝
    Garbage Collection Essence.Net中Garbage Collection深入探讨
    数据结构C#实现二叉查找树的创建,查找,以及各种递归(非递归)遍历算法
    C#中不安全代码的编写和指针的应用
    C#中的安全策略
    系统诊断概述如何通过windbg来dump特定process的memory.
    经典数据结构之栈的应用迷宫问题
    CPU Scheduling进程调度算法
    ASP.NET中将检索出的数据写入Exel形成Report的一种solution
  • 原文地址:https://www.cnblogs.com/BlueskyRedsea/p/9261412.html
Copyright © 2011-2022 走看看