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

【递归、搜索与回溯】穷举vs暴搜vs深搜vs回溯vs剪枝

穷举vs暴搜vs深搜vs回溯vs剪枝

  • 1.全排列
  • 2.子集

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

管他什么深搜、回溯还是剪枝,画出决策树就完事了~~~

1.全排列

题目链接:46. 全排列

题目描述:

在这里插入图片描述

算法原理:

其实这道题本身是一个穷举(枚举)的题,3个数你可以三层for循环,但是如果10个数,100个数呢?对于数多的显然不合适!此时我们就需要借助递归把所有情况都枚举出来。

解决回溯的步骤:

  1. 画出决策树,越详细越好!
  2. 设计代码
    全局变量
    dfs函数
    细节问题

1.画出决策树

就是在暴力枚举这道题过程中如何不重不漏的把所有情况枚举到,就是把自己的想想法按照树的样子画下来。

第一次选择可以直接选123中任何一个,接下来每次选择都是从123中选。但是此时你会发现比如第一次选1,下一次还选1就会有重复的情况,因此这个1我们是要把它剪掉的,不考虑有1的情况。第二次选择假设选择的是2,在往下选择就还是有123,但是此时剪掉的应该更多,12不能选,只能选3,所有最终这条分支就是123,同理其他也是这样选出。
在这里插入图片描述

决策树画的越详细越好,就是把每一步都画出来,这样你就会发现每一个节点干的事情都是一样的,都是枚举整个数组。无非就是一些分支被我们剪掉。当一直在干同一件事情的时候我们决策树就画成功了,因为可以改成递归的代码。

2.设计代码

1.全局变量
全局变量就看这个递归需要什么东西和以及最终要返回什么东西。

全局变量的使用仁者见仁智者见智,也可以把全局变量换成参数在递归函数中传递。看个人选择,不过还是建议使用全局变量

首先来递归要返回的二维数组,再来一个把每次选择都要记录的path。
当path.size() == nums.size() 说明已经找到一个符合的组合,此时把path放到ret里,然后回溯 ,注意要 恢复现场。在说这个之前我们要说一说这个剪枝的事情。

在这里插入图片描述

剪枝怎么解决?就是如果避免下一次选择重复的数字。
此时我们也需要一个数组,弄一个bool 类型的数组。来判断一下该条路径下的数是否已经被使用过了。bool数组中记录nums数组中的数字是否已经被使用过。
check[0] 对应 1, check[1] 对应 2 , check[2] 对应3,check初始化都为false,只有对应数字被使用了 check[i]=true,说明这个数字已经被使用过了,下一次就不要选这个数字了。

在这里插入图片描述

2.dfs函数
仅需关心,某一个节点在干什么事情。

3.细节问题
回溯
当我要回去的时候,需要把这个3干掉,就是向上回去把path最后一个元素干掉,但是别忘记了check也是一个全局的, 你用3的时候会把check对应位置置为true,那你向上返回这个3你都不用了,是不是要把3复原啊。

  1. 干掉 path 最后一个元素
  2. 修改 check 数组
    在这里插入图片描述

剪枝
这里前面说过。

递归出口
遇到叶子节点的时候,直接添加结果。不用在到空了。

这样的题一定是决策树画出来是最重要的,第二步设计代码你想到哪一点写那一点都可以。

class Solution {vector<vector<int>> ret;vector<int> path;bool check[7]={false};
public:vector<vector<int>> permute(vector<int>& nums) {dfs(nums);return ret;}void dfs(vector<int>& nums){if(path.size() == nums.size()){ret.push_back(path);//返回之前可以 回溯 --> 恢复现场return;}for(int i=0;i<nums.size();++i){//剪枝if(check[i] == false){path.push_back(nums[i]);check[i]=true;dfs(nums);//返回之后也可以 回溯 ---> 恢复现场  ,建立返回之后check[i]=false;path.pop_back();      }}}
};

注意一定是决策树越详细后面代码设计越轻松,代码设计考虑一下全局变量、dfs函数、细节问题。

2.子集

题目链接:78. 子集

题目描述:

在这里插入图片描述

算法原理:

这里我们采用两种策略来解决这个问题,虽然是两种策略,但都是深搜,所以我们的思考方式是一样的。

解法一:

  1. 画出决策树
  2. 设计代码
    全局变量
    dfs
    细节:回溯、剪枝、递归出口

首先画决策树,我们想想如何能够把所有子集不重不漏全部枚举出来。我们从子集定义出发,子集是这个数组里面选or不选某些数形成新的集合就是它的子集。因此我们就单独盯着数组中每个数字考虑选or不选来画出我们的决策树。
在这里插入图片描述
此时所有叶子节点就是数组所有不重复的子集。

现在我们仅需把这颗决策树转换成代码就可以了。之前的题无非就是直接把树画好给我们了,现在是要我们自己画一颗树。

既然叶子节点是我们的结果,因此我们需要两个全局变量,一个二维数组ret,一个一维数组path,path把每次选or不选路径记录下来,然后ret把path记录下来。这道题我们并不需要剪枝。

dfs函数我们就盯着某一个位置在干什么。比如绿圈的位置,因为上面已经选过了,所以要需要考虑这一次的数选or不选,所以dfs不仅要这个nums,还要告诉我你当前选到了那个位置,dfs(nums,pos)
就加入到path里,然后dfs(nums,pos+1)下一层
不选直接 dfs(nums,pos+1)下一层
在这里插入图片描述
细节问题:回溯要恢复现场,因此我们在选的这条路径在递归返回之后把path最后一个位置pop掉,剪枝我们这里没有。递归出口当pos==nums.size()的时候,把path放到ret里,然后返回即可。

class Solution {vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums,0);return ret;}void dfs(vector<int>& nums,int pos){if(pos == nums.size()){ret.push_back(path);return;}// 选path.push_back(nums[pos]);dfs(nums,pos+1);path.pop_back(); // 恢复现场// 不选dfs(nums,pos+1);}
};

解法二:
也是上面一样的步骤,

  1. 画出决策树
  2. 设计代码
    全局变量
    dfs
    细节:回溯、剪枝、递归出口

这里我们换一种思考方式,当我们选的子集是没有元素、只有一个元素、只有两个元素、只有三个元素等等。前面的是盯着某一个数选or不选,现在我们直接看看最终要的子集要么没有,要么一个元素,要么两个元素,要么三个元素等等,从小到大去选。并且每次是从这个被选的数的后面再次选。并且每一个节点都是我们想要的结果。

在这里插入图片描述
你会发现我们这种解法比上面少了很多没有必要的情况。

全局变量还是上面那两个,dfs函数 从当前节点位置开始向后枚举,所以也要知道当前位置 dfs(nums,pos)。for(int i=pos;i<nums.size();++i) 把路径上的节点放入path,然后递归到下一层dfs(nums,pos+1),当递归返回收把path最后一个位置pop掉。 回溯也要恢复现场,把path最后一个位置pop掉,这里我们不用剪枝递归出口,每次进入递归函数后先把path先放到ret里。然后也不需要出口,循环条件不满足就出去了。

class Solution {vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums,0);return ret;}void dfs(vector<int>& nums,int pos){ret.push_back(path);for(int i=pos;i<nums.size();++i){path.push_back(nums[i]);dfs(nums,i+1);path.pop_back(); // 恢复现场}}
};

相关文章:

【递归、搜索与回溯】穷举vs暴搜vs深搜vs回溯vs剪枝

穷举vs暴搜vs深搜vs回溯vs剪枝 1.全排列2.子集 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 管他什么深搜、回溯还是剪枝&#xff0c;画出决…...

celery-redbeat方案(动态定时任务、异步任务)

文章目录 为什么选择 RedBeat&#xff1f;方案坑事项记录 记一次工作上的问题 问题&#xff1a;项目上当前定时任务框架和服务端耦合&#xff0c;容易出现加载定时任务时间很长&#xff0c;影响后端服务启动&#xff0c;容易改动引发定时任务的问题。且能方便的动态的增加或删除…...

js解析成语法树以及还原

const {parse} require("babel/parser"); const traverse require("babel/traverse").default; const generator require("babel/generator").default;// 1.定义要处理的代码 const jscode function square(n) {return n * n; };// 2.使用ba…...

基于python可伸缩JSON格式列表实现

对于消息体为一个json格式列表&#xff0c;列表长度变化的代码设计&#xff0c;如下实现可供参考。 1、python语言实现(直接取值) #codingutf-8n 2 # 行项目数 productCode [11111,222222,333333] unit [H06,H07,H08] qty [6,7,8] items []for i in range(0, n):item …...

h5相机功能

h5相机功能 利用vant input file <template><div class"mb10"><divv-for"(item, index) in info.imgList":key"index"class"imgItem f32 mr20"click"preview(item, index)"><img :src"doFileUrl…...

IDEA | 安装通义灵码插件,开启智能编码旅程

安装步骤 从插件市场安装&#xff0c;点击导航-插件&#xff0c;打开应用市场&#xff0c;搜索通义灵码&#xff08;TONGYI Lingma&#xff09;&#xff0c;找到通义灵码后点击安装。 https://tongyi.aliyun.com/lingma/download 使用方式 https://help.aliyun.com/documen…...

技术人员如何克服在使用行列视(RCV)过程中遇到的挑战?

技术人员在使用行列视&#xff08;RCV&#xff09;过程中可能会遇到多种挑战&#xff0c;以下是一些建议&#xff0c;帮助他们克服这些挑战&#xff1a; 1. 深入了解系统架构和功能&#xff1a; - 熟练掌握RCV的架构设计&#xff0c;包括数据中心层、计算服务层、函数层、人机…...

手把手教你安装 Vivado2019.2(附安装包)

一、Vivado 2019.2优点 Vivado 2019.2 作为 Xilinx 公司发布的一款设计套件版本&#xff0c;具有多个显著的优点&#xff0c;以下是对其优点的详细归纳&#xff1a; 集成度高&#xff1a;开发工具丰富并行综合功能灵活的许可证策略用户友好的界面强大的仿真和验证功能丰富的文…...

Sql-labs的第一关

前言 我们在使用Sql-libs靶场进行Sql注入实验的时候&#xff0c;前提要求我们对mysql数据库结构要有一个大概的了解&#xff0c;因为mysql5.0以上的版本都会自带一个名为information_schema的数据库&#xff0c;这个数据库下面会有columns和tables两个表。 tables这个表的table…...

10_1 Linunx Web服务管理

10_1 Linunx Web服务管理 文章目录 10_1 Linunx Web服务管理[toc]1. 环境准备2. Web服务2.1 Web服务简介 2.2 Web配置2.2.1 提供的默认配置2.2.2 Web服务的主配置文件2.2.3 /etc/httpd/conf/httpd.conf 文件反映出来的”访问控制信息“2.2.4 修改监听端口&#xff0c;访问2.2.5…...

苹果WWDC 2024:十三大亮点公布,一切都有关AI|TodayAI

在刚刚结束的苹果全球开发者大会(WWDC 2024)上,苹果公司展示了一系列令人瞩目的新功能,特别是在人工智能(AI)领域的重大进展。以下是本次大会的十三大亮点。 1. 苹果推出首个AI系统 苹果宣布推出其首个AI系统——Apple Intelligence,这一系统将强大的生成模型直接集成到…...

Nginx访问日志

Nginx日志是Nginx Web服务器产生的记录文件&#xff0c;主要用于跟踪和分析服务器的访问情况以及错误信息。Nginx日志主要分为两大类&#xff1a;访问日志 (access_log): 访问日志记录了每一次客户端对Nginx服务器的HTTP请求的详细信息&#xff0c;这对于统计分析、流量监控、用…...

Java使用Hutool工具类轻松生成验证码

一、效果展示 二、Hutool工具类实现验证码生成 2.1 引入依赖 <!--hutool工具包--> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.15</version> </dependency2.2 简单实现方…...

leetcode 40. 组合总和 II

题目 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 原题链接&#xff1a;https://leetc…...

AMEYA360代理品牌:ROHM开发出世界超小CMOS运算放大器,适用于智能手机和小型物联网设备等应用

全球知名半导体制造商ROHM(总部位于日本京都市)开发出一款超小型封装的CMOS运算放大器“TLR377GYZ”&#xff0c;该产品非常适合在智能手机和小型物联网设备等应用中放大温度、压力、流量等的传感器检测信号。 智能手机和物联网终端越来越小型化&#xff0c;这就要求搭载的元器…...

第1章Hello world 4/5:对比Rust/Java/C++创建和运行Hello world全过程:运行第一个程序

讲动人的故事,写懂人的代码 1.7 对比Rust/Java/C++创建和运行Hello world全过程 有了会听懂人类的讲话,还能做记录的编程助理艾极思,他们三人的讨论内容,都可以变成一份详细的会议纪要啦。 接下来,我们一起看看艾极思是如何记录下赵可菲创建和运行Java程序Hello world,…...

golang优雅代码【lock实现】

golang优雅代码【lock实现】 1.局部锁1.1 具体实现方式 本文代码风格来源参考 database/sql 包 更加深刻理解go语言圣经中函数是一等公民 1.局部锁 database/sql源码中使用 withLock(dc, func(){...}) 方法实现局部锁&#xff0c;完美利用了 golang 的 defer 关键字对 入参dc…...

Dijkstra算法(迪杰斯特拉算法)

迪杰斯特拉算法通常用在图的最短路径问题上 而迷宫的最短路径可以用BFS来做&#xff0c;虽然BFS不能用于带权值的迷宫&#xff0c;但是可以对BFS稍微改进&#xff0c;只需要把判断是否走过的数组改为最短路径的数组&#xff0c;在判断是否可走时判断是否比最短的小即可 Dijks…...

用函数指针求a和b中的大者

指针变量也可以指向一个函数。一个函数在编译时被分配给一个入口地址。这个函数入口地址就称为函数的指针。可以用一个指针变量指向函数&#xff0c;然后通过该指针变量调用此函数。 先按一般方法编写程序&#xff1a; 可以用一个指针变量指向max函数&#xff0c;然后通过该指…...

鸿蒙轻内核M核源码分析系列六 任务及任务调度(2)任务模块

任务是操作系统一个重要的概念&#xff0c;是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源&#xff0c;并独立于其它任务运行。鸿蒙轻内核的任务模块可以给用户提供多个任务&#xff0c;实现任务间的切换&#xff0c;帮助用户管理业务程序流程。…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...