【递归、搜索与回溯】综合练习一

综合练习一

  • 1.找出所有子集的异或总和再求和
  • 2.全排列 II
  • 3.电话号码的字母组合
  • 4.括号生成

在这里插入图片描述

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

1.找出所有子集的异或总和再求和

题目链接:1863. 找出所有子集的异或总和再求和

题目描述:

在这里插入图片描述

先找出所有子集,然后把每个子集异或的和加起来返回去。
在这里插入图片描述

算法原理:
这道题和我们上一道思路完全是一模一样,

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

因为我们有上一道题的基础,我们直接就画出决策树
在这里插入图片描述
这里我们需要两个全局变量,一个path记录到沿途每个子集的异或,然后sum负责每个字节的异或和加起来。dfs函数,还是需要一个pos记录当前异或的位置,dfs(nums,pos),回溯利用异或的规则,两个相同的数异或为0。这里也没有剪枝, 递归出口 循环结束就是递归出口。

class Solution {
    int sum=0;
    int path=0;
public:
    int subsetXORSum(vector<int>& nums) {

        dfs(nums,0);
        return sum;
    }

    void dfs(vector<int>& nums,int pos)
    {
        sum+=path;
        for(int i=pos;i<nums.size();++i)
        {
            path^=nums[i];
            dfs(nums,i+1);
            path^=nums[i]; // 恢复现场
        }
    }
};

2.全排列 II

题目链接:47. 全排列 II

题目分析:

在这里插入图片描述

重复的数全排列后会有重复的结果,这道题就是要求去掉重乎之后的全排列

在这里插入图片描述

算法原理:
这道题几乎和全排列1 一模一样,我们就不在细说那些决策树怎么画,代码应该怎么写等等。这里主要就是剪枝的问题。

下面我们边画决策树变分析问题,把全排列所有不重复不漏的情况画出来,越详细越好。 我们只用关心四个位置,每个位置每次从数组中4个数选择一个树放到一个位置上就行了。只用选四次就行了。

第一次可以选第一个1、第二个1、第三个1、2,但是注意这里就存在剪枝的问题了,如果第一个位置还把第二个1和第三个1选上,此时就会存在重复问题!因为后面三个位置是从112中选的。
在这里插入图片描述
此时就出现了第一种剪枝情况

同一个节点的所有分支中,相同的元素只能选择一次

在这里插入图片描述

然后我们再往下走,第二个位置也可以从数组中4个数字中选任意一个。但是第一个1我们要把它剪掉,因为第一个位置已经把第一个1选过了,只能选一次。此时就有了第二种剪枝情况,这个是和全排列1一模一样的。

同一个位置的数,只能使用一次
还是用bool类型的check数组可以实现,check[i] = true 表明已经使用过了,
check[i] = false 说明还没有使用过。
在这里插入图片描述

但是这里还会出现剪枝情况,第一个1不能用,那我可以把第二个1放在第二个位置,但是第三个1不能出现了,因为同一个节点分支相同的数只能出现一次!

在这里插入图片描述
接下来我们就不画了,我们就可以写代码了。代码逻辑和全排列1几乎一模一样,这里我们主要分析,剪枝应该怎么写。剪枝可以从两个角度写。其实就是两个if判定语句。
1.只关心 “不合法” 的分支。 不合法的直接不让递归下去
2.只关心 “合法” 的分支 合法的就递归
虽然是两个角度,但是最终得到结果都是一样的。

只关心 “不合法” 的分支

  1. 当有一个位置已经选了这个数了下一个位置就不能在选这个位置,check[i] == true
  2. 属于同一个分支节点,前面的数和当前的数相等 就不能选当前的数了。nums[i] == nums[i-1],但是这里有一个问题,我们这个数组里面的数字是有序的,可以这样写,如果无序就不能这样写,因此最开始先对数组进行排序。但是还是有问题,目前nums[i] == nums[i-1]这个条件太广泛了,注意看它目前只适用于第一个位置中不选择相同数,但是在第二个位置中又出现第二个1可以选第三个1不选的情况。因此还要再加条件,注意我们是从第一个位置递归下去到第二个位置然后出现相同的位置不选,但是当我们递归返回的时候这个数又可以选了。这个check[i]==true是上一层的和当前属于第二层无关!我们关注的是同一层相同元素只能选一次。因此这个条件是
    nums[i] == nums[i-1] && check[i-1] == false,但是还不够,可能会有越界的风险,因此这个条件最终是 i != 0 && nums[i] == nums[i-1] && check[i-1] == false

在这里插入图片描述
把上面两个条件组合在一起就得到只关心 “不合法” 的分支
在这里插入图片描述

只关心 “合法” 的分支

  1. 当一个数没人选的时候可以选这个数 check[i] == false
  2. 但注意到同一层可能有相同的数,第一个相同的数没人选因为是第一次出现确实是可以选的,但是如果当前的数和前面的数相同即使当前数没人选也是不能选的,因此 还要满足 nums[i] != num[i-1] 只要这个数不和前面相同说明就是第一次出现了绝对可以选!。但是还有一种情况,如果有相同的数字,也就是 nums[i] != num[i-1] 不满足的情况,那就是满足 nums[i] == num[i-1] 前面数和后面数相同的情况,如果上一个位置选了前面的数,那走下到下一个位置的时候,因为这个数已经选过了check[i] == true,其实也就说明这个数是上一个位置的数,和我本次第二个位置选数无关,即使是相同的数子也没有关系,我也是能够选择这个后面相同的数。也就是要满足 check[i-1] == true 前面的相同数被上一个位置选了。还有最后一个情况,刚开始i==0肯定是第一次出现的数并且这个数字没人选的时候,可以选。

在这里插入图片描述

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    bool check[9];
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {

        sort(nums.begin(),nums.end());
        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)
        {
            // 剪枝
            // 1.只关心不合法
            // if(check[i] == true ||(i != 0 && nums[i] == nums[i-1] && check[i-1] == false))
            //     continue;
            
            // path.push_back(nums[i]);
            // check[i]=true;
            // dfs(nums);
            // check[i]=false;
            // path.pop_back();//恢复现场


            // 2.只关心合法
            if(check[i] == false && (i == 0 || nums[i] != nums[i-1] || check[i-1] == true))
            {
                path.push_back(nums[i]);
                check[i]=true;
                dfs(nums);
                check[i]=false;
                path.pop_back();//恢复现场
            }
        }
    }
};

3.电话号码的字母组合

题目链接:17. 电话号码的字母组合

题目分析:

在这里插入图片描述
就是数字对应的字符串进行排列组合。对于这种搜索啊、暴搜啊,我们已经知道要用到递归,回溯、剪枝了。
在这里插入图片描述
算法原理:
有了前面的基础,这个题我们就不写那么步骤了,画出决策树,我们直接写出对应需要的东西。不过在此之前我们需要先将数字与字符串映射关系搞和,我们可以用哈希表映射,或者其他方法,这里最简单的就是弄一个字符串数组把数字和字符串映射一下。

接下来就是画出决策树然后分析一下,首先需要两个全局变量 ret记录结果,path记录每条路径到叶子节点的组合,递归函数 给我一个digits和数字然后递归函数把组合后的结果返回出来,相信它一定能完成任务。dfs(digits,pos),然后回溯 记得恢复现场,递归出口 到叶子节点,这道题没有剪枝

在这里插入图片描述

class Solution {
public:
    string numberletter[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> ret;
    string path;

    vector<string> letterCombinations(string digits) {

        if(digits.empty()) return ret;

        dfs(digits,0);
        return ret;
    }

    void dfs(string& digits,int pos)
    {
        if(pos == digits.size())
        {
            ret.push_back(path);
            return;
        }

        string str=numberletter[digits[pos]-'0'];
        for(int i=0;i<str.size();++i)
        {
            path+=str[i];
            dfs(digits,pos+1);
            path.pop_back();
        }
    }
};

4.括号生成

题目链接:22. 括号生成

题目分析:

在这里插入图片描述
给几对括号,然后把括号组合一下形成 有效括号
在这里插入图片描述
算法原理:
首先我们要知道什么是 有效括号的组合
1.左括号的数量 = 右括号的数量
2.从头开始的任意一个子串,左括号数量 >= 右括号数量

如下面第二种情况,虽然满足条件1但是并不满足条件2,画线字串右括号数量 > 左括号数量
在这里插入图片描述

对于这样暴力枚举的所有情况的问题,我们还是画一颗决策树,把所有情况不重不漏的情况都画出来,然后根据这棵树我们写代码。

每个位置都有两种选择,但是注意到刚开始就有剪枝的情况,刚开始不能选右括号,因为不满足条件2,所以右括号我们要分情况剪枝。当右括号数量大于等于左括号的数量时此时不能添加右括号 right >= left。还有当左括号的数量大于等于n时此时就没有左括号可以选了,left >= n。后面情况都是这样分析的,因此我们就可以做写代码的准备了。
在这里插入图片描述
全局变量,需要一个 left 记录左括号的数量,right 记录右括号的数量,还有一个n记录有几对括号要组合。还需要一个ret记录结果,path记录每条路径的结果。递归函数 每个位置都有两种选择。因为上面都是用的全局变量,因此递归函数参数什么都不用传了。dfs()。回溯 当把path放到ret里,返回后要恢复现场。pop掉path最后一个位置元素。剪枝 前面已经分析了。递归出口 当right==n的时候说明括号组合完了。

class Solution {
public:
    int left=0,right=0;
    vector<string> ret;
    string path;

    vector<string> generateParenthesis(int n) 
    {
        dfs(n);
        return ret;
    }

    void dfs(int& n)
    {
        if(right == n)
        {
            ret.push_back(path);
            return;
        }

        if(left < n) //添加左括号
        {
            path+='(';++left;
            dfs(n);
            path.pop_back();--left;//恢复现场
        }

        if(right<left)//添加右括号
        {
            path+=')';++right;
            dfs(n);
            path.pop_back();--right;//恢复现场
        }

    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年【四川省安全员C证】免费试题及四川省安全员C证考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 四川省安全员C证免费试题是安全生产模拟考试一点通总题库中生成的一套四川省安全员C证考试技巧&#xff0c;安全生产模拟考试一点通上四川省安全员C证作业手机同步练习。2024年【四川省安全员C证】免费试题及四川省安…

linux搭建sftp服务

1. 添加用户及用户组 使用 groupadd sftpgroup 添加sftpgroup 用户组&#xff1b; 使用useradd -G sftpgroup -s /sbin/nologin cmssftp给sftpgroup 添加cmssftp用户&#xff1b; 使用passwd cmssftp给用户cmssftp进行设置密码(默认为:654321)。具体如下图所示&#xff1a; 2.…

云原生Kubernetes系列项目实战-k8s集群+高可用负载均衡层+防火墙

一、Kubernetes 区域可采用 Kubeadm 方式进行安装&#xff1a; 名称主机部署服务master192.168.91.10docker、kubeadm、kubelet、kubectl、flannelnode01192.168.91.11docker、kubeadm、kubelet、kubectl、flannelnode02192.168.91.20docker、kubeadm、kubelet、kubectl、flan…

文心一言 VS 讯飞星火 VS chatgpt (280)-- 算法导论20.4 1题

一、假设 CONNECTED-COMPONENTS 作用于一个无向图 G(V&#xff0c;E)&#xff0c;这里V{a&#xff0c;b&#xff0c;c&#xff0c;d&#xff0c;e&#xff0c;f&#xff0c;g&#xff0c;h&#xff0c;i&#xff0c;j&#xff0c;k}&#xff0c;且 E 中的边以如下的顺序处理:(d…

在Lua解释器中注册自定义函数库

本文目录 1、引言2、注册原理3、实例4、程序验证 文章对应视频教程&#xff1a; 暂无&#xff0c;可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在现代软件开发中&#xff0c;Lua因其轻量级、高效和可嵌入性而被广泛使用。作为一种灵活的脚本语言…

使用uniapp设置tabbar的角标和移除tabbar的角标

使用场景描述 在一进入到小程序的时候就要将用户在购物车中添加的商品总数&#xff0c;要以角标的形式显示在tababr中。 代码实现 //index.vue<script setup> import { onLoad } from dcloudio/uni-apponLoad(()>{uni.setTabBarBadge({index: 1,text: 5 //为了实现…

电商开发者必读:微店商品详情API接口全解析

微店作为一个流行的电商平台&#xff0c;提供了丰富的API接口供开发者使用。详细介绍商品详情API接口的使用方法&#xff0c;帮助开发者快速获取商品信息&#xff0c;实现商品信息的自动化展示和管理。 1. 接口简介 微店商品详情API接口允许开发者通过商品ID获取商品的详细信…

如何使用 Midjourney换脸,将一个人面部复制并粘贴到任意人身上

嘿&#xff0c;想不想将一个人的面部随意粘贴到任意人身上&#xff1f;现在开始教学如何使用 Discord 中的Midjourney Bot 实现&#xff0c;这就是“COPY A FACE”这个超酷的功能&#xff0c;它能帮你一键把脸贴到任何图片上。用到的是一个叫“InsightFace”的开源Discord机器人…

防止数据泄露的软件哪家强?四款防泄密软件助您安心守护企业机密

在信息化时代&#xff0c;企业数据安全成为了关乎生死存亡的关键因素。 数据泄露事件频发&#xff0c;选择一款高效可靠的防泄密软件变得尤为重要。 以下是六款市场上备受推崇的防泄密软件&#xff0c;它们以各自的优势为企业数据安全保驾护航。 1. 域智盾软件 软件以其全面…

Threejs-09、贴图的加载与环境遮蔽强度设置

1、创建文理加载器 let textureLoader new THREE.TextureLoader();2、加载贴图 // 加载文理 let texture textureLoader.load("./img/image.png") // 加载ao贴图 let aoMap textureLoader.load("./img/image.png");3、创建一个平面 let planeGeomet…

预告|博睿数据将受邀出席GOPS全球运维大会北京站!

GOPS全球运维大会作为国内外运维领域最具影响力的技术盛会之一&#xff0c;旨在汇聚全球运维精英&#xff0c;分享运维领域的前沿技术、实践经验与创新理念。6月28日&#xff0c;博睿数据&#xff08;bonree.com&#xff0c;股票代码688229&#xff09;将受邀出席第二十三届 GO…

cdh中的zookeeper怎么配置zoo.cfg

你手动改了zoo.cfg目录是不会生效的&#xff0c;因为是cdh在管控&#xff0c;所以只能通过cdh修改。 首先打开cdh。 xxx:7180 点击zookeeper 选配置&#xff0c;然后选高级 在右边找&#xff0c;有一个就是zoo.cfg&#xff0c;可以点击右边的感叹号。然后在里面编辑的就会直…

ChatGPT中文镜像网站分享

ChatGPT 是什么&#xff1f; ChatGPT 是 OpenAI 开发的一款基于生成预训练变换器&#xff08;GPT&#xff09;架构的大型语言模型。主要通过机器学习生成文本&#xff0c;能够执行包括问答、文章撰写、翻译等多种文本生成任务。截至 2023 年初&#xff0c;ChatGPT 的月活跃用户…

【皇帝的新衣】虚拟小组长的团队管理

团队有时候会需要设立虚拟小组长来分组帮忙管理&#xff0c;那么&#xff0c;虚拟小组的负责人应当怎么做好管理动作&#xff1f; 目前很多大厂追求团队管理上的扁平化&#xff0c;但真正有实职的领导们一般管理30人数&#xff0c;此时需要一个虚拟小组长来分组帮忙管理。 一、…

C# 使用 webview2 嵌入网页

需求&#xff1a;C#客户端程序, 窗口里嵌入一个web网页&#xff0c;可通过URL跳转的那种。并且&#xff0c;需要将登录的身份验证信息&#xff08;token&#xff09;设置到请求头里。 核心代码如下&#xff1a; // 打开按钮的点击事件 private void openBtn_Click(object sen…

Foundation Model 通用大模型的评测体系

随着大模型评测需求逐渐增加,相关研究也进一步深入。大模型相比传统模 型&#xff0c;泛化能力更强、灵活性更高、适应性更广&#xff0c;多任务、多场景&#xff0c;评测维度、评测指标和数 据集更复杂&#xff0c;面向大模型的评估方法、评测基准、测试集成为新的研究课题。 …

不想搭集群,直接用spark

为了完成布置的作业&#xff0c;需要用到spark的本地模式&#xff0c;根本用不到集群&#xff0c;就不想搭建虚拟机&#xff0c;hadoop集群啥的&#xff0c;很繁琐&#xff0c;最后写作业还用不到集群&#xff08;感觉搭建集群对于我完成作业来说没有什么意义&#xff09;&…

【2024最新精简版】Redis面试篇

文章目录 什么是红锁Redis有哪些框架&#xff1f;你们项目中哪里用到了Redis ?Redis的常用数据类型有哪些 ?Redis的数据持久化策略有哪些 ?Redis的数据过期策略有哪些 ?Redis的数据淘汰策略有哪些 ?你们使用Redis是单点还是集群 ? 哪种集群 ?Redis集群有哪些方案, 知道嘛…

【第六篇】SpringSecurity的权限管理

一、权限管理的实现 服务端的各种资源要被SpringSecurity的权限管理控制可以通过注解和标签两种方式来处理。 放开了相关的注解后在Controller中就可以使用相关的注解来控制了 JSR250注解 /*** JSR250*/ @Controller @RequestMapping("/user") public class UserC…

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[1]-最新版快速实践并部署(检索增强生成RAG大模型)

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[1]-最新版快速实践并部署(检索增强生成RAG大模型) 基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现,开源、可离线部署的检索增强生成(RAG)大模型知识库项目。 1.介绍 一种利用 langchain思想实现的基于本地知…