刷题记录 动态规划-7: 63. 不同路径 II

题目:63. 不同路径 II

难度:中等

给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0])。机器人尝试移动到 右下角(即 grid[m - 1][n - 1])。机器人每次只能向下或者向右移动一步。

网格中的障碍物和空位置分别用 1 和 0 来表示。机器人的移动路径中不能包含 任何 有障碍物的方格。

返回机器人能够到达右下角的不同路径数量。

测试用例保证答案小于等于 2 * 109

示例 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

一、模式识别

类似于刷题记录 动态规划-5: 62. 不同路径-CSDN博客,本题我尝试过三种解法:

首先最容易想到的就是基于递归的DFS(深度优先搜索),

然后如果沿着递推公式能想到从终点返回起点这一层就能写出动态规划解法

最后代码随想录还给出了算组合数的方法(数论)

1.DFS

同样地,根据动态规划方法的递推公式可以直接写出基于递归的DFS

2.动态规划

本题属于经典动态规划问题,而且动规的很多要素题干中已经直接给出

五部曲:

1.动规数组意义:位于位置(i, j)时剩余的总步数

2.递推公式:dp(i, j) = dp(i - 1, j) + dp(i, j - 1)

解释:

机器人处于位置(i, j)时,每次只能向下或者向右移动一步两种选择,

分别可以到达(i - 1, j)和位置(i, j - 1),

由于障碍物的存在,会有两类边界情况:

①遇见障碍物dp(i, j) = 0

②当机器人走到边缘位置(i == m - 1 or j == n - 1),路径便只剩下一条:

边缘位置没有障碍物时,路径只剩下一条, dp(i, j) = 1

只要边缘位置有至少一个障碍物,该路径就会被堵死,

不仅时障碍物位置,整条边缘线都被堵死:dp(i, j) = 0

3.初始化:题干:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )

4.遍历顺序:本题常规,根据递推公式:

注意,dp的访问顺序和机器人的寻路顺序完全相反

5.举例:略

3.数论:算组合数

对于无障碍物的情况:

无论怎么走,从起点(m, n)到终点(1, 1)都要走m + n - 2步,

其中,横向m - 1步,纵向n - 1步

因此该问题就顺理成章的转化成了C(m + n - 2), (m - 1)的组合问题

如果有障碍物,我一开始的思路是

有障碍物总数:总数 - 起点到障碍物路数×障碍物到终点路数

但这个思路是不行的!!!我会在后面详述

二、代码实现

1.DFS

这方法很好想,而且代码简洁,

思路是顺着机器人寻路,所以可读性强,只需要把递推公式表达清楚即可

但就是有个小小的问题:会超时!

class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])def helper(i, j):if obstacleGrid[i][j] == 1:return 0if i == m - 1 and j == n - 1:return 1if i == m - 1:return helper(i, j + 1)if j == n - 1:return helper(i + 1, j)return helper(i + 1, j) + helper(i, j + 1)return helper(0, 0)

问题源于其指数级的时间复杂度:O(2^(m + n - 1) - 1)

2.动态规划

注意和代码随想录不一样,

我自己写的时候二维OMN空间写法时直接用obstacleGrid充当dp数组,

所以遍历顺序反序,返回值位置是(0, 0)

(1)二维OMN空间写法

class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])for i in range(m - 1, -1, -1):for j in range(n - 1, -1, -1):if obstacleGrid[i][j] == 1:obstacleGrid[i][j] = 0else:if i == m - 1:if j < n - 1 and obstacleGrid[i][j + 1] == 0:obstacleGrid[i][j] = 0else:obstacleGrid[i][j] = 1elif j == n - 1:if i < m - 1 and obstacleGrid[i + 1][j] == 0:obstacleGrid[i][j] = 0else:obstacleGrid[i][j] = 1else:obstacleGrid[i][j] = obstacleGrid[i + 1][j] + obstacleGrid[i][j + 1]return obstacleGrid[0][0]
  • 时间复杂度:O(m × n)
  • 空间复杂度:O(m × n)

耗时:0ms

(2)一维ON空间写法

class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])dp = [1] * nfor i in range(m - 1, -1, -1):for j in range(n - 1, -1, -1):if obstacleGrid[i][j] == 1:dp[j] = 0else:if i == m - 1:if j < n - 1 and dp[j + 1] == 0:dp[j] = 0else:dp[j] = 1elif j == n - 1:if i < m - 1 and dp[j] == 0:dp[j] = 0else:dp[j] = 1else:dp[j] += dp[j + 1]return dp[0]
  • 时间复杂度:O(m × n)
  • 空间复杂度:O(n)

耗时:0ms

可读性有点差,所以稍微解释一下,和二维空间代码的对应关系:

dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 和 dp[j] += dp[j - 1]

dp[i][j]: 更新后的dp[j]

dp[i - 1][j]: 更新前的dp[j]

dp[i][j - 1]: dp[j - 1]

三、为什么本题不能用算组合数的方法做?

1.欠考虑的情况

如果按照“总数 - 起点到障碍物路数×障碍物到终点路数”的思路,将写出以下代码:

class Solution:def calculate_conbination(self, m, n):num = 1a, b = m + n - 2, min(m - 1, n - 1)count = bwhile count > 0:num *= aa -= 1while b > 0 and num % b == 0:num //= bb -= 1count -= 1return numdef uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])ob = Falsex, y = 0, 0for i in range(m):for j in range(n):if obstacleGrid[i][j] == 1:x, y = i, job = Truereturn self.calculate_conbination(m, n) - (self.calculate_conbination(x + 1, y + 1) * self.calculate_conbination(m - x, n - y)) if ob else self.calculate_conbination(m, n)

然后就会这样:

输入

obstacleGrid =

[[0,1],[1,0]]

输出

1

预期结果

0

因为障碍物可能不止一个!!!

2.改进后发现该方法只能解决某些特殊情况

那继续改进,将公式改进为:总数 - Σ起点到障碍物路数×障碍物到终点路数

然后写出这个代码:

class Solution:def calculate_conbination(self, m, n):num = 1a, b = m + n - 2, min(m - 1, n - 1)count = bwhile count > 0:num *= aa -= 1while b > 0 and num % b == 0:num //= bb -= 1count -= 1return numdef uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])obs = []for i in range(m):for j in range(n):if obstacleGrid[i][j] == 1:obs.append((i, j))ans = self.calculate_conbination(m, n)for x, y in obs:ans -= (self.calculate_conbination(x + 1, y + 1) * self.calculate_conbination(m - x, n - y))return ans

 然后就会这样:

输入

obstacleGrid =

[[0,0,0,0],[0,1,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,0]]

输出

0

预期结果

7

为什么呢?

因为你当障碍物数量超过一个,可能有些路径被重复计算!

所以该方法只适用于障碍物数量少于等一个的情况!!!

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12438.html

    如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    深度求索DeepSeek横空出世

    真正的强者从来不是无所不能&#xff0c;而是尽我所能。多少有关输赢胜负的缠斗&#xff0c;都是直面本心的搏击。所有令人骄傲振奋的突破和成就&#xff0c;看似云淡风轻寥寥数语&#xff0c;背后都是数不尽的焚膏继晷、汗流浃背。每一次何去何从的困惑&#xff0c;都可能通向…

    51c视觉~CV~合集10

    我自己的原文哦~ https://blog.51cto.com/whaosoft/13241694 一、CV创建自定义图像滤镜 热图滤镜 这组滤镜提供了各种不同的艺术和风格化光学图像捕捉方法。例如&#xff0c;热滤镜会将图像转换为“热图”&#xff0c;而卡通滤镜则提供生动的图像&#xff0c;这些图像看起来…

    【论文复现】粘菌算法在最优经济排放调度中的发展与应用

    目录 1.摘要2.黏菌算法SMA原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了一种改进粘菌算法&#xff08;ISMA&#xff09;&#xff0c;并将其应用于考虑阀点效应的单目标和双目标经济与排放调度&#xff08;EED&#xff09;问题。为提升传统粘菌算法&#xf…

    C++基础(2)

    目录 1. 引用 1.1 引用的概念和定义 1.2 引用的特性 1.3 引用的使用 2. 常引用 3. 指针和引用的关系 4. 内联函数inline 5. nullptr 1. 引用 1.1 引用的概念和定义 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开…

    【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.29 NumPy+Scikit-learn(sklearn):机器学习基石揭秘

    2.29 NumPyScikit-learn&#xff1a;机器学习基石揭秘 目录 #mermaid-svg-46l4lBcsNWrqVkRd {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-46l4lBcsNWrqVkRd .error-icon{fill:#552222;}#mermaid-svg-46l4lBcsNWr…

    圆上取点(例题)

    Protecting The Earth &#xff08;圆内取点&#xff09; 题目描述&#xff1a; 给定 K (地球上的人数)&#xff0c;你必须制作一个保护罩来保护他们。(地球上的人数&#xff09;&#xff0c;你必须制作一个保护罩来保护他们。 已知一个人只能站在整数的坐标上&#xff0c…

    【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.19 线性代数核武器:BLAS/LAPACK深度集成

    2.19 线性代数核武器&#xff1a;BLAS/LAPACK深度集成 目录 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…

    [leetcode·回溯算法]回溯算法解题套路框架

    本文参考labuladong算法笔记[回溯算法解题套路框架 | labuladong 的算法笔记] 本文解决几个问题&#xff1a; 回溯算法是什么&#xff1f;解决回溯算法相关的问题有什么技巧&#xff1f;如何学习回溯算法&#xff1f;回溯算法代码是否有规律可循&#xff1f; 其实回溯算法和我…

    SQL Server中RANK()函数:处理并列排名与自然跳号

    RANK()是SQL Server的窗口函数&#xff0c;为结果集中的行生成排名。当出现相同值时&#xff0c;后续排名会跳过被占用的名次&#xff0c;形成自然间隔。与DENSE_RANK()的关键区别在于是否允许排名值连续。 语法&#xff1a; RANK() OVER ([PARTITION BY 分组列]ORDER BY 排序…

    多线程的常用方法

    getName和setName方法 注意点 setName方法最好放在线程启动之前 最好在线程启动之前修改名字&#xff0c;因为线程启动之后&#xff0c;如果执行过快的话&#xff0c;那么在调用 setName() 之前线程可能就已经结束了 MyThread t1 new MyThread("haha"); t1.setNa…

    Unity游戏(Assault空对地打击)开发(6) 鼠标光标的隐藏

    前言 鼠标光标在游戏界面太碍眼了&#xff0c;要隐藏掉。 详细操作 新建一个脚本HideCursor&#xff0c;用于隐藏光标。 写入以下代码。 意义&#xff1a;游戏开始自动隐藏光标&#xff0c;按Esc&#xff08;显示<-->隐藏&#xff09;。 using System.Collections; using…

    【Linux系统】信号:再谈OS与内核区、信号捕捉、重入函数与 volatile

    再谈操作系统与内核区 1、浅谈虚拟机和操作系统映射于地址空间的作用 我们调用任何函数&#xff08;无论是库函数还是系统调用&#xff09;&#xff0c;都是在各自进程的地址空间中执行的。无论操作系统如何切换进程&#xff0c;它都能确保访问同一个操作系统实例。换句话说&am…

    冰蝎v4.0.5 来啦

    webshell始终是渗透测试的热门&#xff0c;上次护网写冰蝎检测规则&#xff0c;加密流量&#xff0c;有点压力&#xff0c;今天终于有空来复现一下&#xff0c;我知道玩知乎的大佬很多&#xff0c;轻一点喷&#xff0c;学习新知识不丢人&#xff5e; ailx10 1949 次咨询 4.9 …

    WPS怎么使用latex公式?

    1、下载并安装mathtype https://blog.csdn.net/weixin_43135178/article/details/125143654?sharetypeblogdetail&sharerId125143654&sharereferPC&sharesourceweixin_43135178&spm1011.2480.3001.8118 2、将mathtype嵌入在WPS MathType面板嵌入器,免费工具…

    基于微信小程序的私家车位共享系统设计与实现(LW+源码+讲解)

    专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

    安全策略配置

    需求: 1、VLAN 2属于办公区;VLAN 3属于生产区 2、办公区PC在工作日时间(周一至周五&#xff0c;早8到晚6)可以正常访问0A Server&#xff0c;其他时间不允许 3、办公区PC可以在任意时刻访问web server 4、生产区PC可以在任意时刻访问0A Server&#xff0c;但是不能访问Web serv…

    【大数据技术】教程05:本机DataGrip远程连接虚拟机MySQL/Hive

    本机DataGrip远程连接虚拟机MySQL/Hive datagrip-2024.3.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本机的DataGrip连接虚拟机的MySQL数据库和Hive数据库,提高编程效率。 安装DataGrip 请按照以下步骤安装DataGrip软…

    响应式编程_01基本概念:前世今生

    文章目录 引言响应式编程的技术优势全栈式响应式编程从传统开发模式到异步执行技术Web 请求与 I/O 模型异步调用的实现技术回调Future机制 响应式编程实现方法观察者模式发布-订阅模式数据流与响应式 响应式宣言和响应式系统 引言 大流量、高并发的访问请求的项目&#xff0c;…

    龙芯+FreeRTOS+LVGL实战笔记(新)——16数码管驱动

    本专栏是笔者另一个专栏《龙芯+RT-Thread+LVGL实战笔记》的姊妹篇,主要的区别在于实时操作系统的不同,章节的安排和任务的推进保持一致,并对源码做了完善与优化,各位可以前往本人在B站的视频合集(图1所示)观看所有演示视频,合集首个视频链接为: https://www.bilibili.…

    正态分布和标准正态分布区别与联系(复习)

    1)区别&#xff1a;正态分布的平均数为μ&#xff0c;标准差为σ&#xff1b;不同的正态分布可能有不同的μ值和σ值&#xff0c;正态分布曲线形态因此不同。 标准正态分布平均数μ0&#xff0c;标准差σ1&#xff0c;μ和σ都是固定值&#xff1b;标准正态分布曲线形态固定。…