【递归,搜索与回溯算法 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(一)
找出所有子集的异或总和再求和
题目解析
算法原理
解法
决策树
这种决策使得每一次递归都是有效的递归,每一个节点都是最终的结果,所以这棵决策树是不用剪枝的,也没有递归出口的;
注意
决策树执行添加元素的操作前,要先从子集末尾元素在 nums 的位置后面是否还有元素,如果有元素则可以添加,反之,则不可以添加;
全局变量
开始时,子集是空集,所以异或的结果为 0 ,path 初始值刚好是0,所以不用处理子集为空的情况;
函数结构
在递归到决策树的某一层时,要知道从 nums 的哪个元素开始向后枚举,因此设计 dfs(nums,pos)
编写代码
虽然没有写 return 来回溯,但是在每次向下递归新一层的 dfs 时,这层 dfs 执行完,就会自动返回上一层的 dfs;
全排列Ⅱ
题目解析
算法原理
这道题其实就是全排列Ⅰ的plus 版本,只是多了重复的数,大体框架和全排列Ⅰ相同,只是剪枝操作需要更细致一点,全排列Ⅰ的解法可以先看下面这篇博客的第一题:
【递归,搜索与回溯算法】穷举 vs 暴搜 vs 深搜 vs 回溯 vs 剪枝算法入门专题详解
两道题唯一的出入的就是剪枝操作,所以我们下面只讲全排列Ⅱ该如何剪枝;
1. 两种剪枝
- 1. 在同一个节点(如图中的黑色节点)的所有分支中,相同的元素只能选择一次:
- 2. 同一个数只能使用一次,可以设置一个 check[] 数组来标记一下用过的数为 true
1.1 根据两种剪枝完善决策树
2. 两种思考方式
本质相同,都是针对是否需要剪枝的情况作出相应的处理 ;
3. 只关心不合法的分支(被剪枝的分支)
红色剪枝条件 check[ i ] == true,表示同一个数只能使用一次
粉色剪枝条件 nums[ i ] == nums [ i -1 ],表示同一个节点的所有分支中,相同数只能使用一次
3.1 问题一:如果 nums 中重复元素不是连在一起的,那么这个判断条件无法使用
3.1.1 问题解析
如果我们要全排列的数组是 [ 1 , 2 , 1 , 3 , 1 ],那么无法判断同一个节点,其中一条分支要递归的数,是否在前面分支中已经出现过了;
3.1.2 解决办法
我们可以在正式递归之前,先对 nums 数组先进行排序,方便后续的剪枝操作;在大多数情况下,排序数组的时间复杂度O(N*logN),对于递归O(2^N)来说可以忽略不记;
3.2 问题二:无法筛查掉红色剪枝的分支,和合法分支相邻的情况
3.2.1 问题解析
nums[ i ] == nums [ i -1 ] 这个对不合法分支的判断条件范围还是太广了,无法筛查掉红色剪枝的分支,和合法分支(不应该被剪枝的分支)相邻的情况;
因为这些分支所代表的数是相同的,所以 nums[ i ] 所在的分支会被识别为不合法分支,而被执行粉色剪枝;
但是实际上,被红色剪枝的 nums[ i -1 ] 所在分支,本身就是不合法分支;
只有当 nums[i-1]和 nums[i] 两条分支都是合法的时候,才需要判断 nums[ i ] 是否等于 nums[ i - 1 ]
3.2.2 解决办法
我们要把下面这两种情况区分开:
那么怎么区分开呢?其实非常简单;就是判断两个数是否在决策树的同一层;
(1) 对于不同层:
两个数不是同一层,哪怕 nums[ i ] == nums [ i - 1 ],nums[ i -1 ] 所在分支肯定也会被执行红色剪枝 ,因此 nums[i] 所在分支就是合法分支;
(2) 对于同一层:
如果递归时发现check[i-1]==false,则说明 nums[i-1] 和 nums[i] 所在位置为决策树同一层,如果是同一层,并且这两个数还相等,此时递归 nums[i] 的分支就是不合法的分支;
(3) 改进条件
我们在准备对 nums [ i ] 进行递归时,先判断 check[i] == false,如果 check[ i -1 ] == false ,那么就可以判断 nums[i-1] 和 nums[i] 在同一层;
对同一层进行进一步判断,如果 nums[i-1] == nums[i],说明 nums[i] 所在分支不合法;
3.3 问题三:i = 0时,访问 nums[ i -1 ] 会越界
只关心不合法分支的最终判断条件: i != 0 && check[ i ] == false && num[i]==nums[i-1]
3.4 总结不合法分支
4. 只关心合法的分支(不被剪枝的分支)
4.1 先判断该节点是否已经被使用(是否会被执行红色剪枝)
如果我们的思考链路是只关心分支合法,那么第一步就是检查该分支是否被红色剪枝:
所以第一步就是判断 check [ i ] == false;
合法分支是一条 不被执行红色剪枝 && 不被执行粉色剪枝 的分支,所以在判断该分支不被执行红色剪枝后,我们就需判断该分支是否被执行粉色剪枝;
4.2 节点未被使用的情况下,是否被执行粉色剪枝
4.2.1 节点在决策树的深度相同,但是代表的数不同
我们先来分析下面这条分支,在检查完 check[ i ] == false 而不被执行红色剪枝之后之后,我们来判断是否被粉色剪枝:
显然,nums[ i ] != nums[ i -1 ],因此肯定不会执行粉色剪枝(nums 已经提取排好序了);
此时的判断条件为 check[ i ] ==false && ( nums [ i ] ! = nums [ i-1] .......)
4.2.2 节点代表的数相同,但是该节点前一条分支已经被使用
如果 nums[ i ] == nums [ i - 1 ],但是 nums[ i - 1 ] 已经被使用过了,此时 check [ i - 1 ] == true,那么此时的分支也是合法的;所以此时的判断条件:
4.2.3 当 i = 0 的情况
如果只是考虑当前分支是否合法,那么 i 是可以等于 0 的;
i = 0 表示的是数组第一个元素,只要确保 check[ 0 ] ==false,就一定是可以大胆枚举的;因为这是对 nums 的第一个元素进行枚举的分支,这条分支必定是合法分支(一定是从考虑合法分支的角度出发);
此时的判断条件:
5. 两种思考方式判断条件的区别
如果考虑当前分支不合法,就需要根据前一条分支的具体情况,来对当前分支的合法与否作出判断,如果当前分支的 i=0,则会出现数组越界;
6. 处理细节问题
7. 编写代码
7.1 只关心不合法分支
7.2 只关心合法分支
电话号码的字母组合
题目解析
算法原理
解法一 : 暴力枚举
定义两层 for 循环,对字符映射的数字的所有组合进行暴力枚举 ;但是如果一个字符映射的数字过多,使用暴力枚举是不好操作的;
解法二 :深度优先遍历
决策树
对决策树进行一次深度优先遍历,在叶子节点收集结果即可;
解决数字和字符串的映射关系
我们可以使用字符串数组,让字符串数组前两个位置空着,让下标为2的数组元素存 "abc" 这个字符串,往后依此类推 ;
我们在遍历原始字符串的时候,拿到字符'2'之后,减去字符' 0 '对应的 Ascii 码值,就可以对应字符串数组的下标元素;
全局变量
设计函数
编写代码
括号生成
题目解析
算法原理
给一个括号子串,必须从头到尾遍历子串的每一个括号字符,如果在遍历的过程中,出现左括号的数量大于右括号的数量,那么这个子串就一定不是有效括号子串 :
解法:暴搜
决策树
- 蓝色剪枝表示添加 ( 数量大于 n 剪枝;
- 紫色剪枝表示添加 ) 数量大于 ( 的数量;
全局变量
这些变量可以设置成全局变量,也可以作为参数传给 dfs,区别在于恢复现场时采取的措施不同;
设置函数
编写代码
组合
题目解析
算法原理
解法 : 暴搜
决策树
根据题目示例可以知道 ,得到的 path ,元素没有顺序可言,path 的区别只在元素的种类,所以可以画出决策树:
- 1. 两层节点代表的数相同,执行紫色剪枝;
- 2. 前面的分支已经枚举过这种可能,执行蓝色剪枝, path 只看元素种类,不看元素顺序
发现规律
所以我们不需要定义全局变量来剪枝,只需要在向下递归时,从当前节点元素的下一个元素开始递归即可;
设置函数
编写代码
目标和
题目解析
算法原理
解法
决策树
这棵决策树是要深度优先遍历的,每一个节点每次递归只能遍历一条分支,而不是在一个节点递归时,同时记录所有分支;通过递归回溯相结合的方式,遍历整棵决策树;
编写代码
path 是全局变量时候的代码(手动回溯)
path 作为参数的代码 (自动回溯)
报错原因:
如果我们提前让 path+= nums[i] ,是真正修改了 path 的状态并且记录 ,那么编译器在帮我们恢现场的时候,只会恢复 pos 的值,而因为 path 的值无法恢复到上次递归前的值;
组合总和
题目解析
算法原理
解法一:暴搜
决策树
红色剪枝:剪去超过 target 的分支
紫色剪枝:剪去重复出现的组合
最终结果
发现规律
从最终的有效递归图,我们可以发现,有效递归都是是从当前节点开始,向后枚举的;
所以我们在进行下一轮递归时,从当前节点开始枚举即可;
编写代码
报错原因:没有考虑以 pos 越界的情况作为递归出口,并且忽略了本题是可以选择重复元素的:
恢复现场的操作是去掉最后一个元素,并且remove() 的 API 也用不对;
解法二
决策树
这棵决策树是的每一层,是在节点和<= target 时,枚举重复元素相加的个数,直到枚举的节点和大于 target;
处理细节问题
(1) 恢复现场的时机
这个解法有一个特别容易被忽略的地方,就是回溯现场的时机,如左下角的两次递归回溯:
第一次回溯,是不能恢复现场的,因为第二次递归,是在第一次递归了0个5的基础上,再多递归1个5;也就是说,对于同一层回溯,只有递归完一个元素能枚举的所有使用次数,才能恢复现场;
并且,恢复现场时,sum 会自动恢复,但是 path 需要我们手动恢复;
(2) 在解法一的基础上修改代码
对于解法二,只是枚举的策略不同,其他的递归,剪枝操作和解法一是相同的;因此,我们只需要删除红色框的代码,在此基础上重新编写即可;
(3) 用于枚举的循环的终止条件
这个循环的小细节是,枚举 nums[pos] 的个数是从0个开始的,当 k* nums[ pos ] > aim,枚举完这个数的所有可能的使用个数:
(4) 在哪里恢复现场?
不要在上面 for 循环恢复现场,出了 for 循环,表示 nums[pos] 的使用个数枚举完毕,此时再恢复现场:
(5) 恢复现场的循环起点
注意:恢复现场的循环从 k=1 开始
因为我们在递归枚举时 ,会枚举 nums[pos] 使用0次的情况(上层 for 循环从 k=0 开始循环):
但是 path 真正添加 nums[pos] 时,nums[pos] 的使用次数是不为0的;所以我们恢复现场要从 k=1 开始;
所以我们手动恢复现场,本质上恢复的的是执行 path.remove(size()-1) 操作 k-1 次,sum 则是因为通过参数传递,编译器会自动帮助我们恢复 sum ;
编写代码
小优化
字母大小写全排列
题目解析
算法原理
解法:暴搜
决策树
我们可以在原字符串 s 上操作,当 s 递归到叶子节点时,把叶子节点的 s 添加到 ret 中;也可以定义一个全局变量 path ,遍历到 s 字符串的字母字符时,就把变或不变的字符(每次只能选一个)添加到 path 上,如果遍历到的是数字,直接添加到 path 后即可;
全局变量
函数设计
编写代码
相关文章:

【递归,搜索与回溯算法 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(一)
找出所有子集的异或总和再求和 题目解析 算法原理 解法 决策树 这种决策使得每一次递归都是有效的递归,每一个节点都是最终的结果,所以这棵决策树是不用剪枝的,也没有递归出口的; 注意 决策树执行添加元素…...

vue3 如何使用 mounted
vue3 如何使用 mounted 在 Vue 3 中,mounted 生命周期钩子用于当组件被挂载到 DOM 中后执行一些操作。 这个钩子非常适合用来执行那些依赖于 DOM 的初始化工作,比如获取元素的尺寸或者是与第三方的 DOM 有关的库进行交互等。 下面是一个简单的 Vue 3 组…...

PostgreSQL JOIN
PostgreSQL中的JOIN操作是一种用于合并两个或多个表的SQL语句,它允许根据某些条件(通常是表之间的外键关系)将相关的数据组合在一起。PostgreSQL支持多种类型的JOIN,包括: CROSS JOIN(交叉连接)…...

mysql(基础语法)
准备一张员工表 /*Navicat Premium Data TransferSource Server : localhost_3306Source Server Type : MySQLSource Server Version : 80037 (8.0.37)Source Host : localhost:3306Source Schema : studymysqlTarget Server Type : MySQLTar…...

【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo
【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo 前言摘要引言Task 相关工作方法SDM-UniPS预处理尺度不变的空间光特征编码器像素采样变压器的非局部交互 PS-Mix数据集 实验结果训练细节评估和时间: 消融实验定向照明下的评估没有对…...

抓取手机HCI日志
荣耀手机 1、打开开发者模式 2、开启HCI、ADB调试 3、开启AP LOG 拨号界面输入*##2846579##* 4、蓝牙配对 5、抓取log adb pull /data/log/bt ./...

【linux】 unshare -user -r /bin/bash命令详解
命令解析 unshare -user -r /bin/bash 是一个 Linux 命令,它用于在新的用户命名空间中运行一个进程(在这个例子中是 /bin/bash)。以下是这个命令的详细解释: 【1. 命令解析】 unshare: unshare 是一个工具,用于从调用…...

微软远程桌面APP怎么用
微软远程桌面(Remote Desktop)客户端(RD Client)是一款由微软开发的应用程序,允许用户通过网络连接远程访问和控制另一台计算机。同时,微软远程桌面RD Client支持多种设备和操作系统,包括Window…...

Android9.x SurfaceView源码分析
前言 本文是继Android 深入理解SurfaceView再次对SurfaceView进行源码分析。 看了下代码,上篇文章是基于Android7.x的,本篇基于Android9.x再次进行分析, Android从7.0开始支持SurfaceView动画,并建议7.0之后使用SurfaceView替代TextureView,这里主要在Android9.0上分析Su…...

MDS-NPV/NPIV
在存储区域网络(SAN)中,域ID(Domain ID)是一个用于区分不同存储区域的关键参数。域ID允许SAN环境中的不同部分独立操作,从而提高效率和安全性。以下是关于域ID的一些关键信息: 域ID的作用&…...

通用人工智能的关键:统一语言描述万物
当今世界,人工智能(AI)正以前所未有的速度推进着人类社会的进步。从最初的简单计算到如今能够执行复杂任务的智能系统,AI 的每一次飞跃都伴随着理解世界能力的显著提升。然而,要实现真正的通用人工智能——即能够像人类…...

JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中
本文为Oracle数据库JSON学习系列的第一篇,讲述如何将JSON文档存储到数据库中,包括了版本为19c和23ai的情形。 19c中的JSON 先来看一下数据库版本为19c时的情形。 创建表colortab,其中color列的长度设为4000。若color的长度需要设为32767&a…...

[前端]HTTP库Axios
一、Axios简介 Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 node.js 环境。它是一个流行的 JavaScript 库,用于发起 HTTP 请求,如 GET、POST、DELETE 等。Axios 提供了易于使用的 API,支持请求和响应的拦截、转换数据格…...

vue3入门教程:reactive函数
基本用法 引入 reactive 首先,你需要从 vue 包中引入 reactive 函数: import { reactive } from vue;创建一个响应式对象 使用 reactive 函数来创建一个响应式对象: const state reactive({count: 0,name: Vue 3 });在这个例子中,…...

SDMTSP:黑翅鸢算法(Black-winged kite algorithm,BKA)求解单仓库多旅行商问题,可以更改数据集和起点(MATLAB代码)
一、黑翅鸢算法BKA 黑翅鸢算法(Black-winged kite algorithm,BKA)由Wang Jun等人于2024年提出,该算法受黑翅鸢的迁徙和掠食行为启发而得。BKA集成了柯西突变策略和领导者策略,增强了算法的全局搜索能力,提…...

叉车作业如何确认安全距离——UWB测距防撞系统的应用
叉车在工业环境中运行,常常需要在狭窄的空间内完成货物的搬运和堆垛,这对操作员的技术水平和安全意识提出了极高的要求。传统的叉车作业依赖操作员的经验和视觉判断来确认安全距离,然而这种方式往往存在误差,特别是在视线受阻或光…...

5-Gin 静态文件服务 --[Gin 框架入门精讲与实战案例]
在使用 Gin 框架开发 Go 语言应用程序时,提供静态文件服务(如 HTML、CSS、JavaScript 文件等)是一个常见的需求。Gin 提供了简单的方法来设置静态文件的路由,使得你可以轻松地将这些资源提供给客户端。 使用 Static 方法 最直接…...

【自动驾驶】3 激光雷达③
5 激光雷达点云检测模型 🦋🦋🦋CenterPoint是Anchor‐Free的3D物体检测器,以点云作为输入,将三维物体在Bird‐View下的中心点作为关键点,基于关键点检测的方式回归物体的尺寸、方向和速度。相比于Anchor‐…...

Vue 3.5 编写 ref 时,自动插入.Value
如果是 Vue 3.2 ,那么可能用的是Volar...

从0到1实现一个RS蓝图系统-概念提出技术栈选型
请不要自我设限,真正好的人生态度,是现在就做,不等、不靠、不懒惰。 ——小野《改变力》 一、什么是蓝图? 蓝图(BluePrint) 是Epic Games 针对虚幻4引擎开发的可视化脚本语言。当你使用蓝图的时候,其实就是在编写代码…...

npm淘宝镜像
通过命令行配置npm的淘宝镜像源和官方镜像源,以及如何安装和使用cnpm来解决安装包卡顿或无法安装的问题。通过设置registry和disturl,配合清理缓存,可以优化npm的下载速度。 1、官方默认镜像 npm config set registry https://registry.n…...

深入解析:Python中的决策树与随机森林
在这个数据驱动的时代,机器学习技术已经成为许多企业和研究机构不可或缺的一部分。其中,决策树和随机森林作为两种强大的算法,在分类和回归任务中表现尤为出色。本文将带领大家深入了解这两种算法在Python中的实现,从基础到实战&a…...

奇怪问题| Chrome 访问csdn 创作中心的时候报错: 服务超时,请稍后重试
Chrome 访问csdn 创作中心的时候报错: 服务超时,请稍后重试用无痕浏览器可以正常访问 关闭代理无效清缓存和Cookies无效。考虑无痕浏览器模式下插件不生效,尝试把chrome 插件也禁用,发现有效,是该扩展程序的缘故...

【Leetcode】1705. 吃苹果的最大数目
文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接🔗 有一棵特殊的苹果树,一连 n n n 天,每天都可以长出若干个苹果。在第 i i i 天,树上会长出 a p p l e s [ i ] apples[i] apples[i] 个苹果&a…...

职业技能赛赛后心得
这是一位粉丝所要求的,也感谢这位粉丝对我的支持。 那么本篇文章我也是分成四个部分,来总结一下这次赛后心得。 赛中问题 那么这里的赛中问题不会只包含我所遇到的问题,也会包含赛中其他选手出现的问题。 那么首先我先说一下我在赛中遇到的…...

从AI换脸到篡改图像,合合信息如何提升视觉内容安全?
本文目录 引言一、AI“真假之战”下的发展现状与考验挑战1.1 视觉内容安全现状与技术分类1.2视觉内容安全企业1.3视觉内容安全领域挑战 二、开山之石:引领视觉内容安全的创新之路2.1合合内容安全系统2.2发起编制相关技术规范2.3参与篡改检测挑战赛 三、视觉内容安全…...

c# 实现一个简单的异常日志记录(异常迭代+分片+定时清理)+AOP Rougamo全局注入
1. 日志目录和文件管理 日志目录:日志文件存储在 ./Exceptions 目录下。日志文件命名:日志文件的命名格式为 yyyy_MM_dd.log,表示当天的日期。如果当天的日志文件大小超过 maxFileSizeBytes(3KB),则会创建…...

webrtc学习----前端推流拉流,局域网socket版,一对多
提示:局域网socket版,一对多 文章目录 [TOC](文章目录) 前言一、教程二、webrtc工作流程三、推流端四、拉流五、socket服务六、效果七、备注总结 前言 WebRTC(Web Real-Time Communication)是一种实时通讯技术,允许网…...

美国加州房价数据分析01
1.项目简介 本数据分析项目目的是分析美国加州房价数据,预测房价中值。 环境要求: ancondajupyter notebookpython3.10.10 虚拟环境: pandas 2.1.1 numpy 1.26.1 matplotlib 3.8.0 scikit-learn1.3.1 2. 导入并探索数据集 通用的数据分析…...

用Python开启人工智能之旅(四)深度学习的框架和使用方法
第四部分:深度学习的框架和使用方法 用Python开启人工智能之旅(一)Python简介与安装 用Python开启人工智能之旅(二)Python基础 用Python开启人工智能之旅(三)常用的机器学习算法与实现 用Pyt…...