算法通过村第十八关-回溯|青铜笔记|什么叫回溯(中篇)
文章目录
- 前言
- 回溯的核心问题
- 撤销操作解释
- 总结
前言
提示:阳光好的时候,会感觉还可以活很久,甚至可以活出喜悦。 --余秀华
回溯是非常重要的算法思想之一,主要解决一些暴力枚举也搞不定的问题(这里埋个坑💣)例如组合、分割、子集、棋盘等等。从性能角度来看回溯算法的效率并不是很高,但是对于暴力也解决不了的问题,它往往很快可以出结果,效率低就可以理解了吧。接下来,就看看回溯的事情吧🤩
回溯的核心问题
递归+局部枚举+放下前任
接着看这个题目:77. 组合 - 力扣(LeetCode)
当n = 4时,我们可以选择的有n有{1,2,3,4}这四种情况,所以我们从第一层到第二层的分支有四个,分别表示可取1,2,3,4.而且这里从左到右取数,取过的数,不在重复取。第一次取1,集合变为2,3,4.因为k= 2,我们也只能再取1个数就可以了,分别取2,3,4.得到的集合就是[1,2]、[1,3]、[1,4]。一次类推:
横向:
每次从集合中选取元素,可选择的范围回逐步收缩,到了取4时就直接返为空了。
继续观察树结构,可以发现,图中每次访问到一个叶子节点(图中的标记处),我们就可以得到一个结果。虽然到最后时空的,但是不影响最终结果。这里相当于从根节点开始每次选择的内容(分支)达到叶子节点时,将其收起起来就是我们想要的结果。
你可以尝试画下n=5,k=3的结果:有没有感觉
从图中我们发现元素个数n相当于树的宽度(横向),而每个结果的元素个数k相当于树的深度(纵向)。所以我们说回溯问题就是一纵一横而已。在分析我们回发现下面几个规律:
- 我们每次选择都是从类似{1,2,3,4},{1,2,3,4}这个样的序列中一个一个选的,这就是为什么说是局部枚举,后面的枚举范围回越来越小。
- 枚举时,我们就是简单的暴露测试而已,一个一个验证,能否满足要求,从上图可以看到,这就是N叉树的遍历过程,一次代码相似度很高。
- 我们再看叶子过程,这部分是不是和(n = 4,k = 2)处理的结果一致,也就说是很明显的递归结构。
到此,我们还有一个问题待解决,就是回溯一般会有一个手动撤销的操作,为什么要这么做呢?
继续观察纵横图:
我们可以看到,我们收集的每个结果不是针对叶子节点的,而是针对树枝的,比如最上层我们首先确定了1,下层我们如果选择了2,那么结果就是{1,2},如果选择了3,结果就是{1,3}.一次类推。现在时怎么确定得到第一个结果时{1,2}之后,得到第二个结果是{1,3}呢?
继续观察纵横图 ,可以看到,我们在得到{1,2}之后将2撤销,再继续使用3,就得到了{1,3},同理也可以得到{1,4},之后这一层就没有了,我们可以撤销1,继续从最上层取2继续进行。
这里对应的代码操作就是先将第一个结果放在临时列表的Path里面,得到第一个结果{1,2},之后就将path里面的内容放进结果列表resultList中,之后,将path里面的2撤销掉,继续寻找下一个结果{1,3},继续将path加入resultList中,然后再次撤销,继续寻找。
现在了解为什么要撤销,看图。这个过程,我们称它“放下前任,继续前进”,后面的回溯大都是这样的思路。
这几条就是回溯的基本规律,了解这一点,我们就可以看看代码是怎么回事了,到此我们看看完整的代码时怎样的:
public List<List<Integer>> combine(int n, int k) {List<List<Integer>> res = new ArrayList<>();if (k <=0 || n < k){return res;}
Deque<Integer> path = new ArrayDeque<>();
dfs(n,k,1,path,res);return res;}
public void dfs(int n,int k,int startIndex,Deque<Integer> path,List<List<Integer>> res){// 递归终止条件,path 等于k(刚好完成一次if (path.size() == k){res.add((new ArrayList<>(path)));return;}// 针对每个节点,这里就是遍历搜索,也就是枚举for(int i = startIndex; i <= n; i++){// 向路径里添加一个数(分支里的取值path.addLast(i);// 搜索起点要加1,就是缩小范围,准备下一轮递归(这里不允许重复dfs(n,k,i + 1,path,res);// 递归之后要做同样的逆向操作,撤销掉path.removeLast();}}
上面代码还有一个问题需要解释:startIndex和i是怎么变化的,为什么要传递到下一层(+ 1)
我们来看看这里的递归循环:
// 针对每个节点,这里就是遍历搜索,也就是枚举for(int i = startIndex; i <= n; i++){// 向路径里添加一个数(分支里的取值path.addLast(i);// 搜索起点要加1,就是缩小范围,准备下一轮递归(这里不允许重复dfs(n,k,i + 1,path,res);// 递归之后要做同样的逆向操作,撤销掉path.removeLast();}
这里的循环有什么作用呢?看看这里,其实来说是一个枚举,第一次n=4,可以选择1,2,3,4四种情况,所以就存在4个分支,for就需要执行4次:
对于第二层来说,第一个数,选择1之后,身下的元素就只有2,3,4了。所以这时候for循环就执行3次,后面的只有2次和1次了。
撤销操作解释
如果你还是不清楚的话,这里就带图详细的走一遍,回溯也就是这个地方有点晕,拿下就是胜利✌。
// 针对每个节点,这里就是遍历搜索,也就是枚举for(int i = startIndex; i <= n; i++){// 向路径里添加一个数(分支里的取值path.addLast(i);// 搜索起点要加1,就是缩小范围,准备下一轮递归(这里不允许重复dfs(n,k,i + 1,path,res);// 递归之后要做同样的逆向操作,撤销掉path.removeLast();}
为什么要remove呢?看下图,当第一层取1时,最底层的遍历从左到右执行,取2,取3,取4.而取3的时候,此时res里面存储的是{1,2},所以这里前提是需要撤销掉2(path.removeLast();)的作用。
这里我们拆解一下递归方法,将递归拆分成函数调用,输出第一条路径{1,2}的步骤如下:
我们在递归说过一个特点:不到南墙不回头,回溯也是这个道理,我们看看这个过程。
然后,怎么在次进行呢,这里就需要撤回一下了,但是如果将这里的remove代码去掉,就会是这个样子:
这里知道遍历完成,然会的就不做撤销,就会下一场进入for循环,也就是回变成{1,2,3}.
path是一个全局的引用的,各个递归的函数是公用的,所以这里处理完{1,2},之后,需要把2撤出去,将1保留,再让三进入,从而得到{1,3}.所以这里不许remove一下的。
同样处理完之后,后续的也是依次处理,需要撤销的,这里也就是不得不处理撤销的操作。
总结
提示:什么叫回溯;保留状态;撤销操作;回溯核心思想;回溯的入门
如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ ("▔□▔)/
如有不理解的地方,欢迎你在评论区给我留言,我都会逐一回复 ~
也欢迎你 关注我 ,喜欢交朋友,喜欢一起探讨问题。
相关文章:

算法通过村第十八关-回溯|青铜笔记|什么叫回溯(中篇)
文章目录 前言回溯的核心问题撤销操作解释总结 前言 提示:阳光好的时候,会感觉还可以活很久,甚至可以活出喜悦。 --余秀华 回溯是非常重要的算法思想之一,主要解决一些暴力枚举也搞不定的问题(这里埋个坑💣…...
generate by chatgpt:应用上线前的checkList(部分是我自己的回答)
prompt 1 想象你是一名高级测试工程师,在应用上线前你需要提供一份checklist,请写出来: 作为一名高级测试工程师,以下是我在应用上线前的检查清单: 功能性测试: 检查所有要素和功能是否正常工作。确保满足了所有用户故事/需求。…...

Redis实战 | 使用Redis 的有序集合(Sorted Set)实现排行榜功能,和Spring Boot集成
专栏集锦,大佬们可以收藏以备不时之需 Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏:https:/…...

基于信号功率谱特征和GRNN广义回归神经网络的信号调制类型识别算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ................................................................ %调制识别 len1 func_f…...

matplotlib从起点出发(10)_Tutorial_10_Layout
使用受约束的绘图干净整洁地将图形合适排列。 受约束的布局会自动调整子图,以便刻度标签、图例和颜色条等装饰不会重叠,同时仍保留用户请求的逻辑布局。 受约束布局类似于“紧密布局”,但它要更灵活。它处理放置在多个轴上的Axes(放置颜色条…...
HTTP头部信息解释分析(详细整理)(转载)
这篇文章为大家介绍了HTTP头部信息,中英文对比分析,还是比较全面的,若大家在使用过程中遇到不了解的,可以适当参考下 HTTP 头部解释 1. Accept: 告诉WEB服务器自己接受什么介质类型,/ 表示任何类型&#…...

集线器、交换机、网桥、路由器、网关
目录 集线器(HUB)交换机(SWITCH)网桥(BRIDGE)路由器(ROUTER)网关(GATEWAY)交换机和路由器的区别参考 集线器(HUB) 功能 集线器对数据的传输起到同步、放大和整形的作用 属于物理层设备 工作机制 使用集线器互连而成的以太网被称为共享式以太网。当某个主机要给另一个主机发送单…...

项目实战:新增@Controller和@Service@Repository@Autowire四个注解
1、Controller package com.csdn.mymvc.annotation; import java.lang.annotation.*; Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Inherited public interface Controller { }2、Service package com.csdn.mymvc.annotation; import java.lang.annotation.*…...
校验 ChatGPT 4.0 真实性的三个经典问题:快速区分 GPT3.5 与 GPT4,并提供免费测试网站
现在已经有很多 ChatGPT 的套壳网站,以下分享验明 GPT-4 真身的三个经典问题,帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 大家可以在这个网站测试:https://ai.hxkj.vip,免登录可以问三条,登录之后无限…...

Jetpack:030-Jetpack中的状态
文章目录 1. 概念介绍2. 使用方法2.1 可监听对象2.2 获取状态值2.3 修改状态值2.4 重组函数 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中网格布局相关的内容,本章回中主要 介绍状态。闲话休提,让我们一起Talk Android Jetpack吧࿰…...

AD教程 (七)元件的放置
AD教程 (七)元件的放置 第一种放置方法 点击右下角Panels,选择SCH Library,调出原理图库器件列表选中想要放置的元件,点击放置,就会自动跳转到原理图,然后放置即可这种方法需要不断打开元件库…...
ubuntu22.04为什么鼠标会自动丢失焦点
排查的步骤 在Ubuntu 22.04中,鼠标自动丢失焦点可能由多种原因引起,包括系统错误、驱动问题、软件冲突或者某些特定的系统设置。以下是一些可能的原因和相应的解决方法: 触控板干扰: 如果你使用的是笔记本电脑,触控板可…...

FastBond2阶段2——基于ESP32C3开发的简易IO调试设备
1. 项目介绍 之前买了许多国产单片机esp32c3一直在吃灰,没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动,刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器(单片机开发测试领域),或者用于国…...

03、SpringBoot + 微信支付 ---- 创建订单、保存二维码url、显示订单列表
目录 Native 下单1、创建课程订单保存到数据库1-1:需求:1-2:代码:1-3:测试结果: 2、保存支付二维码的url2-1:需求:2-2:代码:2-3:测试:…...

【echarts基础】在柱形图上设置文本
一、需求描述 在柱状图上设置文本标签,按需修改它的颜色、大小、边框、阴影等,如下。 二、代码展示 series:[{name:"螺蛳粉",type:"bar",data:data.data.chartData.chartData.num.螺蛳粉,label:{//图形上显示文本标签formatter:&q…...

小户型工业风,陌生上开花知书香。福州中宅装饰,福州装修
漫步陌上 只因陌上花开 花是自然的那种 朴素而恬淡,不落尘俗。—徐志摩 小户型工业风格 满足业主需求 筑造书香押韵家 从动线、色彩、选材、定制等各个环节 与业主一起畅谈家的构造 形成别“居”一格的温暖品质家 以书做墙 告别电视墙 这是一个实用性很强的…...

Gorm 中的迁移指南
探索使用 GORM 在 Go 中进行数据库迁移和模式更改的世界 在应用程序开发的不断变化的景观中,数据库模式更改是不可避免的。GORM,强大的 Go 对象关系映射库,通过迁移提供了一种无缝的解决方案来管理这些变化。本文将作为您全面的指南…...

基于.NET、Uni-App开发支持多平台的小程序商城系统 - CoreShop
前言 小程序商城系统是当前备受追捧的开发领域,它可以为用户提供一个更加便捷、流畅、直观的购物体验,无需下载和安装,随时随地轻松使用。今天给大家推荐一个基于.NET、Uni-App开发支持多平台的小程序商城系统(该商城系统完整开源…...
[python] 在多线程中将`logging.info`输出到不同的文件中 (生产者消费者)
在多线程中将logging.info输出到不同的文件中,可以使用Python标准库中的Queue和Thread模块。具体实现步骤如下: 创建多个Queue队列用于不同线程的日志输出,每个队列对应一个日志文件。 import queue# 创建三个队列用于不同线程的日志输出 l…...

MySQL进阶_5.逻辑架构和SQL执行流程
文章目录 第一节、逻辑架构剖析1.1、服务器处理客户端请求1.2、Connectors1.3、第1层:连接层1.4、第2层:服务层1.5、 第3层:引擎层1.6、 存储层1.7、小结 第二节、SQL执行流程2.1、查询缓存2.2、解析器2.3、优化器2.4、执行器 第三节、数据库…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...