LeetCode刷题复盘笔记—一文搞懂62. 不同路径 63. 不同路径 II(动态规划系列第三篇)
创始人
2024-02-02 21:16:31
0

今日主要总结一下动态规划的两道题目,62. 不同路径 && 63. 不同路径 II

题目一:62. 不同路径

题目描述:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:

在这里插入图片描述

输入:m = 3, n = 7
输出:28
示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向下
    示例 3:

输入:m = 7, n = 3
输出:28
示例 4:

输入:m = 3, n = 3
输出:6

提示:

1 <= m, n <= 100
题目数据保证答案小于等于 2 * 109

本题重难点

这道题目,刚一看最直观的想法就是用图论里的深搜,来枚举出来有多少种路径。

注意题目中说机器人每次只能向下或者向右移动一步,那么其实机器人走过的路径可以抽象为一棵二叉树,而叶子节点就是终点!

如图举例:

62.不同路径
此时问题就可以转化为求二叉树叶子节点的个数
大家如果提交了代码就会发现超时了!
来分析一下时间复杂度,这个深搜的算法,其实就是要遍历整个二叉树。
这棵树的深度其实就是m+n-1(深度按从1开始计算)。
那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)
所以上面深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。

所以深搜不行,考虑动态规划来试一下:
如前面系列文章一文搞懂动态规划系列(第一篇)509. 斐波那契数70. 爬楼梯和一文搞懂746. 使用最小花费爬楼梯所讲:
对于动态规划问题,可以拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。

按照动规五部曲来分析:

  1. 确定dp数组(dp table)以及下标的含义
    dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

  2. 确定递推公式
    想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]。
    此时在回顾一下 dp[i - 1][j] 表示啥,是从(0, 0)的位置到(i - 1, j)有几条路径,dp[i][j - 1]同理。
    那么很自然,dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来。

  3. dp数组的初始化
    如何初始化呢,首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理。

  4. 确定遍历顺序
    这里要看一下递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
    这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。

  5. 举例推导dp数组

如图所示:
在这里插入图片描述

C++代码

方法一、常规动态规划

class Solution {
public:int uniquePaths(int m, int n) {vector> dp(m, vector(n, 0));for(int i = 0; i < m; i++) dp[i][0] = 1;for(int j = 0; j < n; j++) dp[0][j] = 1;for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}
};

时间复杂度:O(n)
空间复杂度:O(n)

方法二、动归空间复杂度优化
其实用一个一维数组(也可以理解是滚动数组)就可以了,但是不利于理解,可以优化点空间,建议先理解了二维,在理解一维,C++代码如下:

class Solution {
public:int uniquePaths(int m, int n) {vector dp(n);for (int i = 0; i < n; i++) dp[i] = 1;for (int j = 1; j < m; j++) {for (int i = 1; i < n; i++) {dp[i] += dp[i - 1];}}return dp[n - 1];}
};

时间复杂度:O(n)
空间复杂度:O(1)

题目二:63. 不同路径 II

题目描述:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

示例 1:

在这里插入图片描述

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

示例 2:
在这里插入图片描述

输入:obstacleGrid = [[0,1],[0,0]]
输出:1

提示:

m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j] 为 0 或 1

本题重难点

这道题相对于上一题62.不同路径就是有了障碍。

第一次接触这种题目的同学可能会有点懵,这有障碍了,应该怎么算呢?

62.不同路径中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了

机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。

按照动规五部曲来分析:

  1. 确定dp数组(dp table)以及下标的含义
    dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

  2. 确定递推公式
    递推公式和62.不同路径一样,dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。
    但这里需要注意一点,因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)。

  3. dp数组的初始化
    但如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。

如图:
在这里插入图片描述
一旦遇到obstacleGrid[i][0] == 1的情况就停止dp[i][0]的赋值1的操作,dp[0][j]同理

  1. 确定遍历顺序
    这里要看一下递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
    这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。

  2. 举例推导dp数组

C++代码

class Solution {
public:int uniquePathsWithObstacles(vector>& obstacleGrid) {int m = obstacleGrid.size();int n = obstacleGrid[0].size();if(obstacleGrid[0][0] || obstacleGrid[m -1][n - 1]) return 0;vector> dp(m, vector(n, 0));for(int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;for(int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){if(obstacleGrid[i][j] == 0){dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}}return dp[m - 1][n - 1];}
};

时间复杂度:O(n)
空间复杂度:O(n)

可以看出来,加了障碍物的不同路径二相比于第一题,最大的不同主要体现在动规五步曲里面的递推公式更新条件判断上和dp数组初始化上面!


总结

动态规划
英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的

对于动态规划问题,可以拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

这篇文章主要总结了一些动态规划解决不含和包含障碍物的不同路径的两道题目,依然是使用动规五部曲,加了障碍物的不同路径二相比于第一题,最大的不同主要体现在动规五步曲里面的递推公式更新条件判断上和dp数组初始化上面!

做每道动态规划题目这五步都要弄清楚才能更清楚的理解题目!


欢迎大家关注本人公众号:编程复盘与思考随笔

(关注后可以免费获得本人在csdn发布的资源源码)

相关内容

热门资讯

面具 -作文 面具 -作文面具是伪装的工具,带上面具无论是欢乐还是悲伤,无论微笑还是流泪;带上面具是坚强还是懦弱,...
我的幸福五年级作文500字【... 我的幸福五年级作文500字 篇一幸福是一种感觉,是一种心灵的满足和快乐。对我来说,我的幸福是来自于家...
学生作文 【推荐】关于学生作文  无论是在学校还是在社会中,大家都经常看到作文的身影吧,作文是人们以书面形式表...
五年级450字作文路程【推荐... 五年级450字作文路程 篇一我的暑假旅行暑假到了,每个人都有属于自己的计划和安排。而我呢,决定和家人...
摘莲蓬作文五年级【精彩6篇】 摘莲蓬作文五年级 篇一摘莲蓬今天是一个晴朗的秋日,我和妈妈一起来到了一个美丽的莲花池。莲花池里的莲花...
云五年级作文(精彩6篇) 云五年级作文 篇一我的暑假生活暑假终于来临了,这是我最期待的时刻。在这个美好的假期里,我过得非常充实...
全家总动员五年级作文650字... 全家总动员五年级作文650字 篇一《全家总动员》是一部非常有趣的电影,讲述了一家人为了拯救家人的餐厅...
兄弟之间的友谊五年级作文【优... 兄弟之间的友谊五年级作文 篇一兄弟之间的友谊兄弟之间的友谊是一种特殊的情感,它是由血缘关系和共同成长...
难忘的事五年级作文(精彩6篇... 难忘的事五年级作文 篇一我的暑假生活今年暑假,我和家人一起去了海边度假,度过了一个难忘的假期。我们选...
自己管自己的作文五年级(精选... 自己管自己的作文五年级 篇一自己的作文一直以来都是我在小学五年级中非常自豪的一项技能。在这个年级里,...
迎春花儿开五年级作文(精选6... 迎春花儿开五年级作文 篇一迎春花儿开春天来了,大自然万物复苏。在我们学校的花坛里,一片绚丽的迎春花正...
时间五年级作文(经典6篇) 时间五年级作文 篇一我的暑假计划暑假马上就要到了,我制定了一个丰富多彩的暑假计划。首先,我打算每天都...
五年级绿豆糖水作文(精彩6篇... 五年级绿豆糖水作文 篇一绿豆糖水的制作过程绿豆糖水是一道非常受欢迎的甜品,制作起来也非常简单。下面我...
五年级孩子以观察晚霞为体裁的... 五年级孩子以观察晚霞为体裁的作文 篇一美丽的晚霞今天傍晚,我看到了一幅美丽的晚霞。晚霞的颜色非常丰富...
小学五年级母爱的作文500字... 小学五年级母爱的作文500字 篇一母爱是世界上最伟大的力量。在我们的成长过程中,母亲的爱无处不在,时...
五年级暑假写去女儿国玩作文(... 五年级暑假写去女儿国玩作文 篇一女儿国是我梦寐以求的地方。暑假的一天,我终于有机会去女儿国玩了!我和...
蚂蚁帝国五年级作文(实用3篇... 蚂蚁帝国五年级作文 篇一:探索蚂蚁帝国的奇妙世界蚂蚁帝国是一个神奇的世界,它隐藏在我们看不见的地方,...
一幅画作文五年级200字(推... 一幅画作文五年级200字 篇一《夏日的乐园》我在学校的美术课上画了一幅画,它是我想象中的夏日乐园。画...
开学第一天五年级作作文69篇... 开学第一天五年级作作文69篇 篇一我的开学第一天 今天是我五年级的第一天,我非常兴奋。早上,我...
阳光总在风雨后五年级作文(最... 阳光总在风雨后五年级作文 篇一五年级作文:阳光总在风雨后在生活中,我们常常会遇到各种各样的挫折和困难...