【Leetcode】63- 不同路径II

问题简述

一个机器人位于一个 m x n 网格的左上角 。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 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

思路分析

该题求解也是分阶段的,而且下一阶段的解是基于上一阶段的解(“最优子结构”),但与后面阶段的解无关(“无后效性”)。因此考虑动态规划来求解。将动态的 状态 定义为到达当前位置的路径数。由于只能向右、向下移动,因此每个位置的可到达路径数取决于其左边位置、上边位置的可到达路径数,状态转移方程为:dp[i][j] = dp[i-1][j] + dp[i][j-1]。如果某位置是障碍物,则到达目前位置的可到达路径数应为0,表示不可到达。在一次遍历网格的过程中就可以求得每个位置的可到达路径数,走到网格右下方时即可获得该问题的最终结果。代码实现起来比较简单。

代码示例

class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])"""注意:dp=[[0]*n]*m 这种方式是错误的二维矩阵初始化方式,因为这样其实只会生成1个具有n+1个元素的列表,真实的m行并不存在,而是m个引用指向同一个列表。应该使用列表推导式来初始化一个m*n的二维矩阵。"""dp = [[0 for col in range(n)] for row in range(m)] # 或 dp=[[0]*n for _ in range(m)] # 先判断起点或终点是否有障碍物,若有则直接返回无可达路线的结果。避免进入后续无用的循环计算,大大节省时间开销。if obstacleGrid[0][0] == 1 or obstacleGrid[-1][-1] == 1:return 0for i in range(m):for j in range(n):if obstacleGrid[i][j] == 1: dp[i][j] = 0elif i < 0 and j < 0:dp[i][j] = 1elif i < 0:dp[i][j] = dp[i][j-1]elif j < 0:dp[i][j] = dp[i-1][j]else:dp[i][j] = dp[i][j-1] + dp[i-1][j]return dp[-1][-1]

算法复杂度

由于遍历一次网格需要双层循环,时间复杂度为 O ( m × n ) O(m\times n) O(m×n)
dp数组记录每个网格上的可达路径数量,空间复杂度为 O ( m × n ) O(m\times n) O(m×n)

🌟改进算法——减少空间复杂度

该算法需要遍历整个网格,因此时间复杂度不可降低。但有没有什么办法可以减少空间复杂度呢?
有,使用 【滚动数组】 。动态规划算法中经常用该方法对dp数组进行降维,减少空间复杂度。
当状态转移只与前几个状态有关时,可以使用滚动数组记录这几个状态,而不是记录之前所有的状态。
在本问题中,原本使用m*n大小的二维数组记录每个状态。但由于dp[i][j] = dp[i][j-1] + dp[i-1][j],状态的转移只与当前位置的上一行(上一行的当前列)、当前行(当前行的左一列)有关,那么我们可以仅用上一行和当前行而不是m行n列去记录之前阶段的状态,另外由于对网格的遍历顺序是从上往下逐行、再在每行中从左往右逐列的,因此实际上只需使用一行状态数组记录网格当前行的最新的状态,就等于为网格当前行的每个位置记录了其 上一行的当前列当前行的左一列 ;如此将空间复杂度由 O ( m × n ) O(m\times n) O(m×n)降低至 O ( n ) O(n) O(n)。代码示例如下:

class Solution:def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:m, n = len(obstacleGrid), len(obstacleGrid[0])if obstacleGrid[0][0] == 1 or obstacleGrid[-1][-1] == 1:return 0dp = [0] * ndp[0] = 1 if obstacleGrid[0][0] == 0 else 0for i in range(m):for j in range(n):if obstacleGrid[i][j] == 1: dp[j] = 0continueif j-1 >= 0 and obstacleGrid[i][j] == 0:# dp数组记录的是当前行每个位置的最新的状态,遍历到第j个位置时,在更新该位置状态值之前:# dp数组j-1位置的元素记录的是网格中第i行第j-1列的数,dp数组j位置记录的是网格中第i-1行第j列的数。dp[j] += dp[j-1]  return dp[-1]

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

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

相关文章

Vue基础:为什么要学Vue3,Vue3相较于Vue2有那些优势?

为什么要学Vue3&#xff1f; 1.框架层面 1.响应式底层API的变化 Proxy 数组下标的修改 对象动态添加属性 解释说明&#xff1a;1.vue2采用的是Object.definePrototype&#xff0c;它每次只能对单个对象中的单个数据进行劫持&#xff0c;所以在Vue2中data()中的数据一多就要进行…

基础IO认识

回顾文件 我们之前认识文件只是在语言程度上理解&#xff0c;但是我们理解的不够彻底&#xff0c;要想真正理解文件要在os上理解。 简单代码认识 1 #include<stdio.h>2 int main(){3 FILE* fpfopen("log.txt","w");4 if(fpNULL){5 p…

leetcode_43.字符串相乘

43. 字符串相乘 题目描述&#xff1a;给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 &q…

蓝桥杯练习系统(算法训练)ALGO-951 预备爷的悲剧

资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 英语预备爷gzp是个逗(tu)比(hao)&#xff0c;为了在即将到来的英语的quiz中不挂科&#xff0c;gzp废寝忘食复习英语附录单词…

SpringBoot 基础简介

目录 1. SpringBoot 概述 1.1. 为什么会有springboot 1.1.1. 传统Spring 的两个缺点 1.1.2. Springboot 功能 2. SpringBoot 快速搭建 2.1. 创建Maven项目​编辑​编辑​编辑 2.2. 导入SpringBoot起步依赖 2.3. 定义controller 2.4. 添加引导类 2.5. 启动访问 3. Sprin…

Hardened Ubuntu 24.04 LTS发布

Ubuntu 24.04 有了LTS 版本&#xff0c;就是长期稳定支持版 侧重安全的增强加固版本Hardened Ubuntu 24.04 LTS也随之到来。 hardened Linux 自 2022 年推出以来&#xff0c;支持 amd64/x86_64 和 arm64 硬件架构&#xff0c;并提供 AWS 版本和 on-premise 版本&#xff0c;获…

使用node调用chrome(基于selenium-webdriver包)

下载测试版chrome和chromedriver https://googlechromelabs.github.io/chrome-for-testing/ 把chromedriver复制到chrome的文件里 设置环境变量 编写代码 const { Builder, Browser, By, Key, until } require(selenium-webdriver) const puppeteer require(puppeteer)//查…

Spring 如何解决 Bean 循环依赖

循环依赖解释 bean A 属性注入时依赖bean B &#xff0c;并且bean B属性注入时也依赖bean A &#xff0c;造成 bean A 和bean B 都无法完成初始化问题&#xff0c;形成了闭环。 注意 项目中存在Bean的循环依赖&#xff0c;是Bean对象职责划分不明确、代码质量不高的表现&#…

2024/5/2 英语每日一段

Enablers’ fate is inherently linked to adopters, which are their ultimate customers, after all. That dynamic won’t flip overnight, but adopters able to demonstrate progress on AI initiatives will increasingly get credit from investors in the form of high…

基于SSM的“一汽租车辆共享平台”的设计与实现(源码+数据库+文档+PPT)

基于SSM的“一汽租车辆共享平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 登录界面 租车界面 订单管理界面 财务报表界面 理赔界面 …

I/O体系结构和设备驱动程序

I/O体系结构 为了确保计算机能够正常工作&#xff0c;必须提供数据通路&#xff0c;让信息在连接到个人计算机的CPU、RAM和I/O设备之间流动。这些数据通路总称为总线&#xff0c;担当计算机内部主通信通道的作用。 所有计算机都拥有一条系统总线&#xff0c;它连接大部分内部…

Java | Leetcode Java题解之第63题不同路径II

题目&#xff1a; 题解&#xff1a; class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int n obstacleGrid.length, m obstacleGrid[0].length;int[] f new int[m];f[0] obstacleGrid[0][0] 0 ? 1 : 0;for (int i 0; i < n; i) {for (i…

二叉树的递归详解:以例题计算二叉树第k层为例

1.代码速览 1.1节点的构建 #include<iostream> using namespace std; class ListNode { public:friend void fun();friend int TreeKLevel(ListNode* root, int k);ListNode(int val):_val(val),leftnext(nullptr),rightnext(nullptr){} private:int _val 0;class Lis…

【doghead】ubuntu构建libuv

按照官方的文档2024年3月的版本。首先构建libuv 最终构建的还得了test 构建过程 zhangbin@DESKTOP-1723CM1:/mnt/d/XTRANS/thunderbolt/ayame/zhb-bifrost$ ls Bifrost-202403 README.md draw player-only worker 大神的带宽估计.png zhangbin@DESKTOP-1723CM1:/mnt/d/XTRANS/…

Codeforces Round 943 (Div. 3)A-D

div3补提 https://codeforces.com/contest/1968 A&#xff1a;需要求gcd(x,y)y的最大值,给的范围只有1-1000&#xff0c;可以直接暴力来做。 求最大公约数的代码gcd&#xff0c;如果x<y,需要叫交换x和y的值&#xff0c;如果y等于0&#xff0c;就返回x&#xff0c;用递归的形…

240503-关于VisualStudio2022社区版的二三事

240503-关于VisualStudio2022社区版的二三事 1 常用快捷键 快捷键描述AltEnter选中代码片段以提取方法Alt上下箭头移动选中的代码片段F12转到方法定义CtrlR*2批量修改选中的变量名称 2 自动生成构造函数 3 快速重写父类方法 4 节约时间&#xff1a;写代码使用“头插法”&…

Python面试十问2

一、如何使用列表创建⼀个DataFrame # 导入pandas库 import pandas as pd# 创建一个列表&#xff0c;其中包含数据 data [[A, 1], [B, 2], [C, 3]]# 使用pandas的DataFrame()函数将列表转换为DataFrame df pd.DataFrame(data, columns[Letter, Number]) # 列名# 显示创建的…

华为OD机试 - 会议室占用时间段(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

matlab绘制散点图

在MATLAB中&#xff0c;可以使用scatter函数来绘制散点图。下面是一个简单的例子&#xff0c;说明如何使用scatter函数来绘制散点图。 假设你有一组x坐标和一组y坐标&#xff0c;你想在图上绘制它们&#xff1a; % 创建x和y的随机数据 x randn(1, 100); % 从正态分布中生成…

【iOS】pthread、NSThread

文章目录 前言一、pthread 使用方法pthread 其他相关方法 二、 NSThread创建、启动线程线程相关用法线程状态控制方法NSThread 线程安全和线程同步场景 线程的状态转换 前言 五一这两天准备将GCD相关的知识完&#xff0c;同时NSOperation与NSThread、pthread也是相关知识&…