当前位置: 首页 > news >正文

代码随想录算法训练营第39天 | ● 62.不同路径 ● 63. 不同路径II

文章目录

  • 前言
  • 一、62.不同路径
  • 二、63.不同路径II
  • 总结

前言

动态规划


一、62.不同路径

  • 深搜
  • 动态规划
  • 数论

深搜:

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

如图举例:

62.不同路径

此时问题就可以转化为求二叉树叶子节点的个数,代码如下:

class Solution {
private:int dfs(int i, int j, int m, int n) {if (i > m || j > n) return 0; // 越界了if (i == m && j == n) return 1; // 找到一种方法,相当于找到了叶子节点return dfs(i + 1, j, m, n) + dfs(i, j + 1, m, n);}
public:int uniquePaths(int m, int n) {return dfs(1, 1, m, n);}
};

这棵树的深度其实就是m+n-1(深度按从1开始计算)。

那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)

所以上面深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。


动态规划:

  1. 定dp数组(dp table)以及下标的含义

dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

  1. 确定递推公式

想要求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]只有这两个方向过来。

  1. dp数组的初始化

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

所以初始化代码为:

for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
  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]一定是有数值的。

  1. 举例推导dp数组

如图所示:

62.不同路径1

代码:

class Solution {public int uniquePaths(int m, int n) {int dp[][] = new int[m][n];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];}
}


数论:

在这个图中,可以看出一共m,n的话,无论怎么走,走到终点都需要 m + n - 2 步。

62.不同路径

在这m + n - 2 步中,一定有 m - 1 步是要向下走的,不用管什么时候向下走。

那么有几种走法呢? 可以转化为,给你m + n - 2个不同的数,随便取m - 1个数,有几种取法。

那么这就是一个组合问题了。

求组合的时候,要防止两个int相乘溢出! 所以不能把算式的分子都算出来,分母都算出来再做除法。

需要在计算分子的时候,不断除以分母,代码如下:

class Solution {
public:int uniquePaths(int m, int n) {long long numerator = 1; // 分子int denominator = m - 1; // 分母int count = m - 1;int t = m + n - 2;while (count--) {numerator *= (t--);while (denominator != 0 && numerator % denominator == 0) {numerator /= denominator;denominator--;}}return numerator;}
};
  • 时间复杂度:O(m)
  • 空间复杂度:O(1)

计算组合问题的代码还是有难度的,特别是处理溢出的情况!

二、63.不同路径II

动规五部曲:

  1. 确定dp数组(dp table)以及下标的含义

dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

  1. 确定递推公式

递推公式和62.不同路径一样,dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。

但这里需要注意一点,因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)。

所以代码为:

if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i][j]dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
  1. dp数组如何初始化

在62.不同路径

(opens new window)不同路径中我们给出如下的初始化:

vector<vector<int>> dp(m, vector<int>(n, 0)); // 初始值为0
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;

因为从(0, 0)的位置到(i, 0)的路径只有一条,所以dp[i][0]一定为1,dp[0][j]也同理。

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

如图:

63.不同路径II

下标(0, j)的初始化情况同理。

所以本题初始化代码为:

vector<vector<int>> dp(m, vector<int>(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循环的终止条件,一旦遇到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 - 1][j] 和 dp[i][j - 1]一定是有数值。

代码如下:

for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {if (obstacleGrid[i][j] == 1) continue;dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}
}
  1. 举例推导dp数组

拿示例1来举例如题:

63.不同路径II1

对应的dp table 如图:

63.不同路径II2

class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;int n = obstacleGrid[0].length;int dp[][] = new int[m][n];if(obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1){return 0;}for(int i = 0;i<m && obstacleGrid[i][0] ==0;i++){dp[i][0] = 1;}for(int i = 0;i<n && obstacleGrid[0][i] ==0;i++){dp[0][i] = 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];}else{dp[i][j] = 0;}}}return dp[m-1][n-1];}
}


总结

今天去看《奥本海默》。

相关文章:

代码随想录算法训练营第39天 | ● 62.不同路径 ● 63. 不同路径II

文章目录 前言一、62.不同路径二、63.不同路径II总结 前言 动态规划 一、62.不同路径 深搜动态规划数论 深搜&#xff1a; 注意题目中说机器人每次只能向下或者向右移动一步&#xff0c;那么其实机器人走过的路径可以抽象为一棵二叉树&#xff0c;而叶子节点就是终点&#…...

《网站建设:从规划到发布的全过程详解》

一、引言 在数字时代&#xff0c;网站已经成为企业和个人在互联网上的重要存在。一个优质网站的建立需要周全的规划、设计、开发、测试和发布。本文将详细介绍网站建设的全过程&#xff0c;帮助读者了解和掌握网站建设的流程和方法。 二、网站建设的意义 网站建设具有以下意…...

1分钟实现 CLIP + Annoy + Gradio 文搜图+图搜图 系统

多模态图文搜索系统 CLIP 进行 Text 和 Image 的语义EmbeddingAnnoy 向量数据库实现树状结构索引来加速最近邻搜索Gradio 轻量级的机器学习 Web 前端搭建 文搜图 图搜图 CLIP图像语义提取功能&#xff01;...

用树形dp+状压维护树上操作的计数问题:0902T3

发现操作数 k ≤ 6 k\le6 k≤6&#xff0c;可以考虑对操作进行状压。 然后找找性质&#xff0c;发现要么删掉一棵子树&#xff0c;要么进去该子树。可以视为每种操作有两种情况。 然后分讨一下当前该如何转移。 树形dp的顺序&#xff1a; 合并子树考虑当前往上的边的方向 …...

【python爬虫】批量识别pdf中的英文,自动翻译成中文上

不管是上学还是上班,有时不可避免需要看英文文章,特别是在写毕业论文的时候。比较头疼的是把专业性很强的英文pdf文章翻译成中文。我记得我上学的时候,是一段一段复制,或者碰到不认识的单词就百度翻译一下,非常耗费时间。本文提供批量识别pdf中英文的方法,后续文章实现自…...

Android笔记--Hilt

Hilt 是 Android 的依赖项注入库&#xff0c;可减少在项目中执行手动依赖项注入的样板代码。执行手动依赖项注入要求您手动构造每个类及其依赖项&#xff0c;并借助容器重复使用和管理依赖项。依赖注入的英文是Dependency Injection&#xff0c;简称DI,简单说一个类中使用的依赖…...

Oracle常用权限处理

对于Oracle来说&#xff0c;用户等于Schema&#xff0c;创建用户即创建Schema -- 创建用户 create user TCK_TEXT identified by "TCKTCK"; --赋予登陆权限 grant connect to TCK_TEXT; --查看权限列表 select * from user_role_privs ; select * from user_sys_priv…...

Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作

Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作 目录 Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作 一、简单介绍 二、汉化操作 附录&#xff1a; 一、Install from URL 中出现 Failed to connect to 127.0.0.1 port 7890: Connection refused 错误&#xf…...

r 安装源码包 安装本地r包

总结一下手动安装R包 - 简书 (jianshu.com)https://www.jianshu.com/p/2a7a36414734 #BiocManager::install("simplifyEnrichment") #BiocManager::install("EnsDb.Hsapiens.v86")#下载包 之后 手动安装 #install.packages("~/datasets/EnsDb.Hsapien…...

webservice调用对接第三方系统

#webservice调用对接第三方系统# 最近接到一个任务&#xff0c;需要对接第三方数据&#xff0c;第三方提供对接方式的是通过webservice调用&#xff0c;webservice调用有好几种方式&#xff0c;具体可以自行了解&#xff0c;我选择的是通过wsdl文件自动生成客户端代码对接。 …...

实现不同局域网文件共享的解决方案:使用Python自带HTTP服务和端口映射

文章目录 1. 前言2. 本地文件服务器搭建2.1 python的安装和设置2.2 cpolar的安装和注册 3. 本地文件服务器的发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 数据共享作为和连接作为互联网的基础应用&#xff0c;不仅在商业和办公场景有广泛的应用…...

[Android 四大组件] --- Activity

1 Activity是什么 ​​Activity​​是一个Android的应用组件&#xff0c;它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口&#xff0c;窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。 一个应用通常是由多个彼此松散联系的Activity组成&…...

shell中for循环输出1-6

介绍单for循环的语法&#xff0c;以及对数字的循环使用 1、语法介绍 for 变量 in 值列表 do #执行的命令或代码块 Done其中&#xff0c;变量是用来存放每个值的变量名&#xff0c;值列表是需要遍历值的集合&#xff0c;在每次循环中&#xff0c;变量会被设置为值列表中的一…...

docker 04.更加重要的命令

之前的都是基础命令&#xff0c; 前台交互进程和后台守护进程&#xff1a; 重新进入容器&#xff1a; docker中的导入导出&#xff1a; docker中的拷贝到&#xff1a;...

【理解线性代数】(二)线性运算和线性空间

1. 从112看线性运算 11为什么等于2&#xff1f;其实11等于2有一个前提条件&#xff0c;那就是必须在线性运算规则下进行。什么是线性运算规则呢&#xff1f; 理解起来很简单&#xff0c;在一条直线上&#xff0c; 一米的直线长度一米的直线长度两米的直线长度 两个数相加的结…...

专业的视觉特效处理包,FxFactory 8 Pro for Mac助您打造精彩视频

FxFactory 8 Pro for Mac是一款强大的视觉特效处理包&#xff0c;专门为Mac用户设计。它集成了超过200种高质量的视觉效果和过渡效果&#xff0c;可以轻松地应用于各种视频项目中。该软件提供了一个直观的界面&#xff0c;用户可以通过简单拖放操作将特效应用到视频片段上。它支…...

Darshan日志分析

标头 darshan-parser 输出的开头显示了有关作业的总体信息的摘要。还可以使用–perf、–file或–total命令行选项生成其他作业级别摘要信息。 darshan log version&#xff1a;Darshan 日志文件的内部版本号。compression method&#xff1a;压缩方法。exe&#xff1a;生成日志…...

python中如何不修改字符串的前提,使其对大小写字母不敏感

如果你希望在不修改原字符串的基础上实现大小写不敏感的比较&#xff0c;你可以使用内置函数str.casefold()&#xff0c;它会将字符串转换为小写并处理一些特殊字符&#xff0c;使得比较更加严格。下面是如何使用它来实现大小写不敏感的比较&#xff1a; x input() y input()…...

聊聊Http服务化改造实践

在微服务架构体系中远程RPC调用主要包括Dubbo与Http调用两个大类&#xff0c;由于Dubbo拥有服务注册中心&#xff0c;并且起服务的命名非常规范&#xff0c;使用包名.类名.方法名进行描述。 而http调用通常都是使用httpclient等相关类库&#xff0c;这些在使用上并没有问题&am…...

docker打包部署

打包成容器命令 docker build -f ./Dockerfile-long -t 名称.打包镜像 tar docker save -o 名称.tar 名称:latest执行sudo -i&#xff0c;提示输入用户密码&#xff0c;输入密码后进入超级用户&#xff08;root&#xff09;模式 linux上传文件 rz -ytar恢复成镜像 sudo docker…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

Easy Excel

Easy Excel 一、依赖引入二、基本使用1. 定义实体类&#xff08;导入/导出共用&#xff09;2. 写 Excel3. 读 Excel 三、常用注解说明&#xff08;完整列表&#xff09;四、进阶&#xff1a;自定义转换器&#xff08;Converter&#xff09; 其它自定义转换器没生效 Easy Excel在…...