刷题记录 动态规划-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.mzph.cn/pingmian/69094.shtml

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

    相关文章

    HarmonyOS:给您的应用添加通知

    一、通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景&#xff1a; 显示…

    使用Java操作Redis数据类型的详解指南

    SEO Meta Description: 详细介绍如何使用Java操作Redis的各种数据类型&#xff0c;包括字符串、哈希、列表、集合和有序集合&#xff0c;提供代码示例和最佳实践。 介绍 Redis是一种开源的内存数据结构存储&#xff0c;用作数据库、缓存和消息代理。它支持多种数据结构&#…

    Unity飞行代码 超仿真 保姆级教程

    本文使用Rigidbody控制飞机&#xff0c;基本不会穿模。 效果 飞行效果 这是一条优雅的广告 如果你也在开发飞机大战等类型的飞行游戏&#xff0c;欢迎在主页搜索博文并参考。 搜索词&#xff1a;Unity游戏(Assault空对地打击)开发。 脚本编写 首先是完整代码。 using System.Co…

    图论常见算法

    图论常见算法 算法prim算法Dijkstra算法 用途最小生成树&#xff08;MST&#xff09;&#xff1a;最短路径&#xff1a;拓扑排序&#xff1a;关键路径&#xff1a; 算法用途适用条件时间复杂度Kruskal最小生成树无向图&#xff08;稀疏图&#xff09;O(E log E)Prim最小生成树无…

    车载软件架构 --- 基于AUTOSAR软件架构的ECU开发流程小白篇

    我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…

    在CentOS服务器上部署DeepSeek R1

    在CentOS服务器上部署DeepSeek R1,并通过公网IP与其进行对话,可以按照以下步骤操作: 一、环境准备 系统要求: CentOS 8+(需支持AVX512指令集)。 硬件配置: GPU版本:NVIDIA驱动520+,CUDA 11.8+。 CPU版本:至少16核处理器,64GB内存。 存储空间:原始模型需要30GB,量…

    nlp文章相似度

    1. 基于词袋模型&#xff08;Bag of Words&#xff09; 方法&#xff1a; 将文本表示为词频向量&#xff08;如TF-IDF&#xff09;&#xff0c;通过余弦相似度计算相似性。 优点&#xff1a;简单快速&#xff0c;适合短文本或主题明显的场景。 缺点&#xff1a;忽略词序和语…

    Linux 传输层协议 UDP 和 TCP

    UDP 协议 UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度如果校验和出错, 就会直接丢弃 UDP 的特点 UDP 传输的过程类似于寄信 . 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接不可靠: 没有确认机制, 没有重传机制; 如果因…

    Android学习21 -- launcher

    1 前言 之前在工作中&#xff0c;第一次听到launcher有点蒙圈&#xff0c;不知道是啥&#xff0c;当时还赶鸭子上架去和客户PK launcher的事。后来才知道其实就是安卓的桌面。本来还以为很复杂&#xff0c;毕竟之前接触过windows的桌面&#xff0c;那叫一个复杂。。。 后面查了…

    unity学习26:用Input接口去监测: 鼠标,键盘,虚拟轴,虚拟按键

    目录 1 用Input接口去监测&#xff1a;鼠标&#xff0c;键盘&#xff0c;虚拟轴&#xff0c;虚拟按键 2 鼠标 MouseButton 事件 2.1 鼠标的基本操作 2.2 测试代码 2.3 测试情况 3 键盘Key事件 3.1 键盘的枚举方式 3.2 测试代码同上 3.3 测试代码同上 3.4 测试结果 4…

    深度剖析八大排序算法

    欢迎并且感谢大家指出我的问题&#xff0c;由于本人水平有限&#xff0c;有些内容写的不是很全面&#xff0c;只是把比较实用的东西给写下来&#xff0c;如果有写的不对的地方&#xff0c;还希望各路大牛多多指教&#xff01;谢谢大家&#xff01;&#x1f970; 在计算机科学领…

    在深度学习中,样本不均衡问题是一个常见的挑战,尤其是在你的老虎机任务中,某些的中奖倍数较高

    在深度学习中,样本不均衡问题是一个常见的挑战,尤其是在你的老虎机任务中,某些的中奖倍数较高 在深度学习中,样本不均衡问题是一个常见的挑战,尤其是在你的老虎机任务中,某些的中奖倍数较高而其他的中奖倍数较低。这种不均衡会导致模型偏向于高频样本(低中奖倍数的),…

    04树 + 堆 + 优先队列 + 图(D1_树(D10_决策树))

    目录 一、引言 二、算法原理 三、算法实现 四、知识小结 一、引言 决策树算法是一种常用的机器学习算法&#xff0c;可用于分类和回归问题。它基于特征之间的条件判断来构 建一棵树&#xff0c;树的每个节点代表一个特征&#xff0c;每个叶节点代表一个类别或回归值。决策…

    简单介绍一下什么是OpenFeign

    OpenFeign是什么&#xff1f; OpenFeign是一个声明式的Http客户端&#xff0c;它可以用来发起Http请求 它主要用于SpringCloud微服务之间的通讯&#xff0c;让调用另一个服务的Java方法和调用本地方法一样快速和便捷 之前我们是用RestTemplate写一大堆东西发起Http请求远程调…

    Hugging Face GGUF 模型可视化

    Hugging Face GGUF 模型可视化 1. Finding GGUF files (检索 GGUF 模型)2. Viewer for metadata & tensors info (可视化 GGUF 模型)References 无知小儿&#xff0c;仙家雄霸天下&#xff0c;依附强者才是唯一的出路。否则天地虽大&#xff0c;也让你们无路可走&#xff0…

    Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践

    title: Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践 date: 2025/2/4 updated: 2025/2/4 author: cmdragon excerpt: PostgreSQL 作为开源关系型数据库的佼佼者,因其强大的功能与性能被广泛应用于各种项目中。而 Python 则因其简洁易用的语法、丰富的库和强大的…

    Vant框架:助力移动端开发的利器

    Vant框架&#xff1a;助力移动端开发的利器 在移动互联网飞速发展的今天&#xff0c;开发一款用户体验出色、界面美观且功能强大的移动端应用并非易事。而Vant框架&#xff0c;作为一款专为移动端设计的Vue.js UI组件库&#xff0c;凭借其轻量级、高度可定制化以及丰富的组件库…

    生成式AI安全最佳实践 - 抵御OWASP Top 10攻击 (上)

    今天小李哥将开启全新的技术分享系列&#xff0c;为大家介绍生成式AI的安全解决方案设计方法和最佳实践。近年来&#xff0c;生成式 AI 安全市场正迅速发展。据 IDC 预测&#xff0c;到 2025 年全球 AI 安全解决方案市场规模将突破 200 亿美元&#xff0c;年复合增长率超过 30%…

    《LLM大语言模型深度探索与实践:构建智能应用的新范式,融合代理与数据库的高级整合》

    文章目录 Langchain的定义Langchain的组成三个核心组件实现整个核心组成部分 为什么要使用LangchainLangchain的底层原理Langchain实战操作LangSmithLangChain调用LLM安装openAI库-国内镜像源代码运行结果小结 使用Langchain的提示模板部署Langchain程序安装langserve代码请求格…