【递归、搜索与回溯】穷举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(); // 恢复现场}}
};

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

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

相关文章

使用API有效率地管理Dynadot域名,创建文件夹管理域名

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

李廉洋:6.11黄金原油持续震荡上行,今日行情走势分析策略。

黄金消息面分析&#xff1a;上周黄金市场的走势受到了PCE通胀数据和美联储政策预期的显着影响。尽管市场对黄金的长期看涨情绪依然存在&#xff0c;但短期内金价的波动性预计将持续。4月份的PCE通胀数据显示价格压力有所降温&#xff0c;这一结果与分析师预期一致&#xff0c;但…

分享一些班组长日常管理工作的经验

在企业管理中&#xff0c;班组长作为基层的管理者和执行者&#xff0c;扮演着至关重要的角色。他们不仅要确保生产任务的顺利完成&#xff0c;还要负责团队建设、员工激励和沟通协调等工作。本文&#xff0c;深圳天行健精益管理咨询公司旨在分享一些班组长日常管理工作的经验&a…

探索C# 10.0的关键新特性

前言 随着.NET 6的发布&#xff0c;C# 10.0带来了许多创新特性和改进&#xff0c;旨在简化编码过程&#xff0c;增强开发者的生产力&#xff0c;并提供更现代、简洁的编程体验&#xff0c;可以说&#xff0c;这些新特性不仅增强了C#的表达能力&#xff0c;还提高了开发者的编程…

【c语言】文件操作,解开你的疑惑

文件操作 为什么使用文件什么是文件文件的分类文件名 二进制文件和文本文件文件的打开与关闭流与标准流流标准流 文件指针文件的打开与关闭 文件的顺序读写文件的随机读写文件读取结束的判定文件缓冲区 为什么使用文件 我们程序运行的数据是运行在内存中的&#xff0c;当成程序…

实用Python:文件与目录管理的17个技巧

今天我们要一起探索的是Python编程中的一个非常实用且基础的领域——文件与目录管理。无论是处理个人数据、自动化办公任务还是构建复杂的软件系统&#xff0c;这些技巧都将大大提升你的工作效率。准备好了吗&#xff1f;让我们一起动手吧&#xff01; 1. 打开与读取文件 目标…

三生随记——梦魇之枕

第一章&#xff1a;搬入新家 在迷雾笼罩的小镇边缘&#xff0c;伫立着一座年代久远的木屋。李晴站在屋外&#xff0c;打量着这座看似平静却充满神秘感的居所。因为工作的原因&#xff0c;她不得不暂时搬离喧嚣的城市&#xff0c;来到这个陌生的地方。 木屋内部陈旧却别有一番风…

品牌渠道健康发展的关键与方法

一个品牌的渠道健康与否对其长期发展至关重要。品牌虽多&#xff0c;但并非所有产品都能成为品牌&#xff0c;创建品牌需大量精力&#xff0c;而让品牌长久健康发展则需多方面努力。 力维网络服务众多知名品牌&#xff0c;总结出一些渠道治理方法供品牌参考。首先&#xff0c;管…

【linux】(7)文本分析awk

awk 用于分析、过滤和生成报告。 基本用法 awk pattern {action} filename常用选项 -F&#xff1a;指定字段分隔符 awk -F, {print $1} filename例子&#xff1a;使用逗号作为字段分隔符&#xff0c;并打印第一列。 -v&#xff1a;定义变量 awk -v varvalue BEGIN {print va…

分享5款让大家电脑更好用的软件

​ 电脑是我们日常生活和工作中不可缺少的工具&#xff0c;今天给大家推荐了五款让电脑更好用的软件。 1.系统清理——CCleaner ​ CCleaner是一款系统优化和隐私保护工具&#xff0c;可以清理无用文件、浏览器缓存、回收站内容等&#xff0c;释放磁盘空间&#xff0c;提升系…

【linux网络(二)】网络基础之套接字编程

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux网络 1. 前言2. 端口号详…

2024下半年软考中级系统集成项目管理师应该如何备考?

2024年软考系统集成项目管理工程师安排在下半年考试&#xff0c;今天跟大家分享一下软考中级系统集成项目管理师的考试备考规划。 报考要求 系统集成项目管理师考试报名没有任何学历、年龄、职业等条件的限制&#xff0c;只要年满18岁就可以报名。 适合人群 各政府部门及事…

任何成为一名优秀的AI产品经理,看完这篇就懂了

&#xff08;背景:之前做AI咨询&#xff0c;对接公司内部AI产品经理经理&#xff0c;外部也对接过很多甲方AI产品经理。后来出来也拿过好几家公司AI产品经理的offer&#xff09; 1.AI产品经理是什么 回答这个问题前我们首先得理清楚什么是AI产品经理&#xff0c;它和传统的互…

JavaLambda表达式 - 操作数组

在Java中&#xff0c;Lambda表达式通常与函数式接口一起使用&#xff0c;以便能够以更简洁的方式表示函数或操作。然而&#xff0c;Java的数组本身并不直接支持Lambda表达式&#xff0c;因为数组是原生数据类型&#xff08;对于基本类型数组&#xff09;或对象的固定大小的集合…

nginx安装和配置ModSecurity

ModSecurity 是一个开放源代码的 Web 应用防火墙 (WAF)&#xff0c;可以帮助保护 Web 服务器免受各种攻击。以下是如何在 Nginx 上安装和配置 ModSecurity 的详细步骤。 一. 安装 ModSecurity &#xff08;1&#xff09;. 安装依赖 在安装 ModSecurity 之前&#xff0c;需要先…

半导体光电子学最后总结(3)光子晶体

Matrix theory 波传输矩阵 (Wave-Transfer Matrix) 散射矩阵 (Scattering Matrix) 光在均匀介质中的传播公式矩阵化 Relation between Scattering Matrix and Wave-Transfer Matrix 级联系统的投射/反射系数&#xff1a;艾里公式 (Airy Formulas) 无损对称系统 斜入射波的传输…

❤vue2项目webpack打包的优化策略

❤ vue2项目webpack打包的优化策略 &#xff08;优化前&#xff09; 现在我们的打包时间为&#xff1a; >打包体积大小为&#xff1a; 1、去除开发环境和生产环境提示以及日志 开发环境和生产环境的打印处理 生产环境去除console.log打印的两种方式 通过环境变量控制co…

终成大流:CDM+AI彻底重塑数据备份市场

进入2024年&#xff0c;CDM市场又迎来高光时刻。 先有Cohesity上演“蛇吞象”并购Veritas数据备份与数据管理业务&#xff0c;并在新一轮融资中获得IBM、NVIDIA两大巨头的战略投资&#xff1b;后有Rubrik获得资本市场认可&#xff0c;以64亿美元市值成功登陆纽交所。两大CDM明…

[Unity学习] 背景视差因子计算,远近背景移动距离差

public Camera cam;public Transform trans;Vector2 startPosiotion;float startZ;//此物距离trans的z距离private float zDistance > transform.position.z - trans.transform.position.z;void Start(){startPosiotion transform.position;startZ transform.position.z;}…

免费!快速!干货!手把手教你如何在个人电脑上搭建你自己的大模型服务!

大模型发展如火如荼&#xff0c;虽然大模型的能力强大&#xff0c;但是大模型也是非常昂贵的&#xff01;不管是训练还是推理&#xff0c;都需要耗费大量的机器&#xff0c;而且机器的硬件资源&#xff0c;比如GPU、TPU等都有一定的要求。 因此&#xff0c;业界的同行们&#x…