【动态规划】LeetCode-64.最小路径和

🎈算法那些事专栏说明:这是一个记录刷题日常的专栏,每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目,在这立下Flag🚩

🏠个人主页:Jammingpro

📕专栏链接:算法那些事

🎯每日学习一点点,技术累计看得见

题目

题目描述

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

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

执行示例

示例 1:

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]

输出:7

解释:因为路径 1→3→1→1→1 的总和最小。

示例2:

输入:grid = [[1,2,3],[4,5,6]]

输出:12

提示

m == grid.length

n == grid[i].length

1 <= m, n <= 200

0 <= grid[i][j] <= 200

题解

由题目可知,我们只能向下走或者向右走。反过来说,到达第i行第j列,其上一步是第i-1行第j列项下走1步,或者是第i行第j-1列向右走1步。例如:第0行第0列元素可以向下走到第1行第0列,或者向右走1步到第0行第1列,如下图左图所示。例如:第1行第1列元素可以从第0行第1列元素向下走1步到达,可以是从第1行第0列向右走1步到达。

题目要求到达右下角的最小路径和,我们可以使用一个dp表(二维数组)来保存到达第i行第j列的最小路径和。由于我们只能向下或向右走,所以第0行元素初始化规则为:dp[0][0]=grid[0][0],余下元素为dp[0][i]=dp[0][i-1]+grid[0][i]。同理,第0列元素初始化规则为:dp[0][0]=grid[0][0],余下元素为dp[i][0]=dp[i-1][0]+grid[i][0]。示例1的第0行和第0列初始化示意图如下↓↓↓

而余下的元素的最小路径求解公式为dp[i][j]=min(dp[i][j-1],dp[i-1][j])+grid[i][j]。也就是说,到达当前位置可以从上一行同列元素向下走1步到达,也可以从上一列同一行元素向右走1步到达,选择从上到下还是从左到右,取决于哪个的最小路径和更小。下图演示示例1的执行过程↓↓↓

经过上面的分析,我们可以得到如下代码↓↓↓

cpp 复制代码
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>>dp(m, vector<int>(n));
        dp[0][0] = grid[0][0];
        //初始化第0行
        for(int i = 1; i < n; i++)
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        //初始化第0列
        for(int i = 1; i < m; i++)
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++)
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        return dp[m - 1][n - 1];
    }
};

上面的代码中,我们专门使用两处循环用于初始化第0行和第0列。我们可以通过对dp表增开1行1列,并将增开的1行1列的dp[0][1]和dp[1][0]初始化为0,余下元素初始化INT_MAX,即可省去上述初始化过程。构建的dp表如下图所示,其中※所在位置,对应上个代码的dp表。

ps:为什么要这么初始化呢?因为从我们总结出的公式dp[j][j]=min(dp[i-1][j], dp[i][j-1])+grid[i-1][j-1]可以看到,求解dp[0][0]时,min(dp[i-1][j], dp[i][j-1])为0,则不会影响其结果;求解余下第0行和第0列的元素时,由于min(dp[i-1][j], dp[i][j-1]),则一定不会选择INT_MAX,而会选择第0行的前1列元素或第0列的前1行元素。

上述思路实现的代码如下,代码行数确实有所减少↓↓↓

cpp 复制代码
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>>dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[0][1] = dp[1][0] = 0;
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
        return dp[m][n];
    }
};

本文存在不足,欢迎留言或私信批评、指正。希望我的解决方法能够对你有所帮助~~

今日打卡完成,点亮小星星☆→★

相关推荐
qq_4335545421 分钟前
C++ 面向对象编程:递增重载
开发语言·c++·算法
带多刺的玫瑰42 分钟前
Leecode刷题C语言之切蛋糕的最小总开销①
java·数据结构·算法
巫师不要去魔法部乱说1 小时前
PyCharm专项训练5 最短路径算法
python·算法·pycharm
qystca1 小时前
洛谷 P11242 碧树 C语言
数据结构·算法
冠位观测者2 小时前
【Leetcode 热题 100】124. 二叉树中的最大路径和
数据结构·算法·leetcode
悲伤小伞2 小时前
C++_数据结构_详解二叉搜索树
c语言·数据结构·c++·笔记·算法
m0_675988233 小时前
Leetcode3218. 切蛋糕的最小总开销 I
c++·算法·leetcode·职场和发展
佳心饼干-5 小时前
C语言-09内存管理
c语言·算法
dbln5 小时前
贪心算法(三)
算法·贪心算法
songroom6 小时前
Rust: offset祼指针操作
开发语言·算法·rust