题目

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

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

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

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

说明:m 和 n 的值均不超过 100。

示例 1:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii

思路

该题是上一题62. 不同路径的升级版,多了一个障碍物而已。可以参照上一题的解题思路。

只要将经过障碍物的路径数设成0即可。

代码

代码都是基于62. 不同路径修改而来的。

递归

class Solution(object):def unique(self, obstacleGrid, m, n):# 如果遇到障碍物,返回0if obstacleGrid[n][m] == 1:return 0# 如果到达了起点,就是一种解法if m == 0 and n == 0:return 1ways = 0# 如果可以向左回退一步if m >= 1:ways = self.unique(obstacleGrid, m - 1, n)# 如果可以向上回退一步if n >= 1:ways += self.unique(obstacleGrid, m, n - 1)return waysdef uniquePathsWithObstacles(self, obstacleGrid):""":type obstacleGrid: List[List[int]]:rtype: int"""# n行 m 列的列表n, m = len(obstacleGrid), len(obstacleGrid[0])return self.unique(obstacleGrid, m - 1, n - 1)

为了能使用上一题的代码,n, m = len(obstacleGrid), len(obstacleGrid[0])这里求出了这个列表的行数与列数,并且传入递归函数中。

if obstacleGrid[n][m] == 1:return 0

基本在递归函数中只加了这段代码而已,非常简单。

虽然思路是对的,但是递归的方式是比较低效的,这里导致了计算超时。参阅LeetCode刷题之动态规划思想,我们可以将其改成记忆化搜索的方式,解决重叠子问题。

记忆化搜索

dp = {}
class Solution(object):def unique(self, obstacleGrid, m, n):if (m,n) not in dp:# 如果遇到障碍物,返回0if obstacleGrid[n][m] == 1:dp[(m,n)] = 0return 0# 如果到达了起点,就是一种解法if m == 0 and n == 0:dp[(m,n)] = 1return 1ways = 0# 如果可以向左回退一步if m >= 1:ways = self.unique(obstacleGrid, m - 1, n)# 如果可以向上回退一步if n >= 1:ways += self.unique(obstacleGrid, m, n - 1)dp[(m,n)] = waysreturn dp[(m,n)]def uniquePathsWithObstacles(self, obstacleGrid):# n行 m 列的列表n, m = len(obstacleGrid), len(obstacleGrid[0])return self.unique(obstacleGrid, m - 1, n - 1)

记忆化搜索的修改方式也很容易。


但是又说我记忆化搜索的代码错误了,实际上进行测试时是对的。


不管,改成动态规划。

动态规划

class Solution(object):def uniquePathsWithObstacles(self, obstacleGrid):""":type obstacleGrid: List[List[int]]:rtype: int"""# n行 m 列的列表n, m = len(obstacleGrid), len(obstacleGrid[0])# n行 m 列的列表dp = [[0] * m for _ in range(n)]#做一个小优化,如果起点就是障碍,那么无解if obstacleGrid[0][0] == 1: return 0else:dp[0][0] = 1# 先设定好边界值,设置第一列的边界值for i in range(1, n):# 如果当前格子不是是障碍 且上一个格子可达if obstacleGrid[i][0] != 1 and dp[i - 1][0] != 0 :dp[i][0] = 1# 否则当前格子不可达# 设置第一行的边界值for j in range(1, m):if obstacleGrid[0][j] != 1 and dp[0][j - 1] != 0:dp[0][j] = 1for i in range(1, n):for j in range(1, m):# 如果当前格不是障碍,才能计算if obstacleGrid[i][j] != 1:# dp[i][j] = 左边一步加上面一步的结果dp[i][j] = dp[i - 1][j] + dp[i][j - 1]return dp[-1][-1]

这里设定边界值的时候要麻烦一点。


如上图所示,用"X"表示障碍物,如果障碍物出现在了边界上,障碍物和右边的格子都是不可达的。
考虑到这个情况就可以了。

#做一个小优化,如果起点就是障碍,那么无解
if obstacleGrid[0][0] == 1: return 0
else:dp[0][0] = 1

并且增加对起点的判断,使得下面设定边界值的代码for循环的range都可以从1开始:

# 先设定好边界值,设置第一列的边界值
for i in range(1, n):# 如果当前格子不是是障碍 且上一个格子可达if obstacleGrid[i][0] != 1 and dp[i - 1][0] != 0 :dp[i][0] = 1# 否则当前格子不可达# 设置第一行的边界值
for j in range(1, m):if obstacleGrid[0][j] != 1 and dp[0][j - 1] != 0:dp[0][j] = 1

LeetCode刷题——63. 不同路径 II相关推荐

  1. leetcode刷题:不同路径II

    分析: 我们用 f(i, j)f(i,j) 来表示从坐标 (0, 0)(0,0) 到坐标 (i, j)(i,j) 的路径总数,u(i, j)u(i,j) 表示坐标 (i, j)(i,j) 是否可行,如 ...

  2. LeetCode-动态规划基础题-63. 不同路径II

    描述 63. 不同路径II 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角 ...

  3. leetcode刷题:不同路径

    题目: 分析:因为题目要求只能向右和向下走动一格. 经过分析可得如下代码 从左上角到右下角的过程中,我们需要移动 m+n-2m+n−2 次,其中有 m-1m−1 次向下移动,n-1n−1 次向右移动. ...

  4. leetcode题库--63不同路径 II

    不同路径 这题就是一个组合问题. int fun(int num){int ans = 1;while(num){ans*=num;num--;}return ans;}int uniquePaths ...

  5. ​LeetCode刷题实战81:搜索旋转排序数组 II

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  6. ​LeetCode刷题实战375:猜数字大小 II

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  7. Java实现 LeetCode 63 不同路径 II(二)

    63. 不同路径 II 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在 ...

  8. LeetCode:63. 不同路径 II

    题目链接 63. 不同路径 II 题目描述 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图 ...

  9. C#LeetCode刷题-剑指Offer

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#LeetCode刷题-剑指Offer | .Net中文网. C#LEETCODE刷题概述 概述 所有LeetCode剑指Offer ...

  10. C#LeetCode刷题-树

    树篇 # 题名 刷题 通过率 难度 94 二叉树的中序遍历 61.6% 中等 95 不同的二叉搜索树 II 43.4% 中等 96 不同的二叉搜索树 51.6% 中等 98 验证二叉搜索树 22.2% ...

最新文章

  1. 供销合作社对话中国农民丰收节交易会 谋定为农服务主业
  2. mysql安装模块解释_MySQL的模块不能安装的解决方法_MySQL
  3. 《深入理解Linux内核》笔记5:内存管理
  4. 《掌门1对1微服务体系 Solar | 阿里巴巴 Sentinel 落地实践》
  5. PHP和MySQL的交互实验注意事项,PHP 和 MySQL 开发中要注意的8个技巧
  6. PyTorch深度学习快速实战入门《pytorch-handbook》
  7. 读《JavaScript语言精粹(修订版)》心得
  8. 为什么每天工作那么努力,却无法突破职场瓶颈?
  9. oracle-pl/sql之二
  10. 【转】C#中Json和类的相互转化
  11. 解决jupyter无法自动打开网页
  12. Java/Spring/SpringBoot利用itextpdf将JPG/PNG/TIF等输出为PDF(解决TIF多页合并问题)
  13. 关于用数组实现输入字符串以单词为元素反转输出思路
  14. Shiro框架Given final block not properly padded问题解决
  15. 第十三届蓝桥杯大赛软件赛省赛(Java 大学C组)
  16. 理解以太坊 Serenity - 第二部分: Casper
  17. ByVal和ByRef的区别
  18. 高精地图:激光雷达点云与高精地图融合
  19. 那个给三千人算命的大师,正在给自己水滴筹
  20. python画指数函数图像_Python3.0科学计算学习之绘图(一

热门文章

  1. 深度学习网络架构(三):VGG
  2. 通过在jquery中添加函数发送ajax请求来加载数据库数据,以json的格式发送到页面...
  3. ViewPager,使用Fragment实现
  4. 【C++】atoi与stoi
  5. [转]在这新站如何在一天内被Google和百度收录
  6. 【洛谷 3905】道路重建
  7. 跨域 webpack + vue-cil 中 proxyTable 处理跨域
  8. CentOS 7 重装mysql编译过程报错解决方法
  9. 绕过限制,申请Google+
  10. HAPPY 2010