【蓝桥杯速成】| 11.回溯 之 子集问题

题目一:子集

问题描述

78. 子集 - 力扣(LeetCode)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

解题步骤

根据前面的做题经验,这一题应该比较容易AC

有没有觉得数组所有可能的子集很像我们每一层遍历的结果,

所以关于子集问题,我们需要的结果不是叶子结点,而是所有结点

那么其它代码逻辑不变,我们只需要改一下收集结果的位置即可

把result.push_back(path);这行代码从终止条件中拿出来

就表示我们每一步都会执行这一句,

空集是所有集合的子集,那么刚调用这个backtracking函数我们就会先加入[]

后面就是遍历一下就加入一下,输出顺序是纵深的,因为这里用的递归调用

对于终止条件,即用完数组所有元素,

那么我们用于指向遍历元素的startindex必然大于等于nums.size()

但其实也可以不加终止条件,因为我们的for循环会让i<nums.size(),它已经结束了

完整代码如下!

code

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums,int startindex){//返回的是每个结点result.push_back(path);if(startindex>=nums.size()){return;}for(int i=startindex;i<nums.size();i++){path.push_back(nums[i]);backtracking(nums,i+1);path.pop_back();}}vector<vector<int>> subsets(vector<int>& nums) {backtracking(nums,0);return result;}
};

题目二:子集②

问题描述

90. 子集 II - 力扣(LeetCode)

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

解题步骤

这题与上一题的区别就在于nums数组中可能包含重复元素

那么这个关键点和我们之前做过的组合总和②是一样的处理

重点就在于去重

我们需要排掉所有在同一层上相同的结果

但同时保证纵向不会被误判,因为纵向取数产生的数字重复,并不意味着答案重复

纵向是不断把子集变长的过程,加进来的都是从数组中取出的,

取出动作并不存在重复,哪怕数字一样但它不是从nums的同一位置取出的!

所以这一题我们要在单层遍历中加入去重代码即可

if(i>0 && nums[i]==nums[i-1] && used[i-1]==False)

为了方便判断重复元素,我们在主函数中会先对nums数组进行排序

那么遍历到第i个元素就可以通过 nums[i]==nums[i-1]这个代码判断是否出现重复元素

为了保证nums[i-1]合法,所以i必须大于0,

因为每次操作我们会用used数组标记数字的使用情况,

在纵向的递归中,used[i]=used[i-1]=true

但在同层当中,由于前一步存在回溯,我们的used[i-1]==false

翻译一下就是,上一层用过后放回去假装没用过

符合以上条件就是我们的重复元素,那么直接continue不需要继续执行

完整代码如下,需要注意在主函数中定义used数组和对nums数组进行排序!

code

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums,int startindex,vector<bool>& used){//返回的是每个结点result.push_back(path);for(int i=startindex;i<nums.size();i++){if(i>0 && nums[i]==nums[i-1] && used[i-1]==false){//去重continue;}path.push_back(nums[i]);used[i]=true;backtracking(nums,i+1,used);used[i]=false;path.pop_back();}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {vector<bool> used(nums.size(), false);sort(nums.begin(),nums.end());backtracking(nums,0,used);return result;}
};

题目三:非递减子序列

问题描述

491. 非递减子序列 - 力扣(LeetCode)

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

示例 2:

输入:nums = [4,4,3,2,1]
输出:[[4,4]]

提示:

  • 1 <= nums.length <= 15
  • -100 <= nums[i] <= 100

解题步骤

这一题可以看成上一题的升级版,它在要求不重复的情况下同时要求该子序列递增

但需要注意的是这里的子序列是按照原数组排序生成的,

我们不能使用sort函数,不然结果也是不正确的

所以我们要换一种去重逻辑

但仍旧需要做到只除去同一层的重复项

不除去纵向的重复元素

那么排序不能用,used数组也就不能用了,

我们需要一个新的辅助,对于去重首选unordered_set,

可以利用find函数很快检查到是否已经出现过

那么我们在处理这一层元素前就需要先定义好这个uset

unordered_ser<int> uset;

再进入到遍历逻辑中,挨个检查元素是否符合题意

如果该元素之前已经用过,那么它必然可以在uset中找到

所以第一个不符合的情况是

if(uset.find(nums[i])!=uset.end())

要确保子序列递增,那么nums[i]不能小于当前path的最后一个元素,即path.back()

为防止出现path为空时的错误,先判断path.empty()为false

则第二个不符合情况如下

if(!path.empty() && nums[i]<path.back)

 可以合并这两种情况,continue

没有出现以上情况,则处理该结点

把nums[i]加入uset中做记录

再加入该数到path中

递归调用后回溯

uset.insert(nums[i]);

path.push_back(nums[i]);

backtracking(nums,i+1);

path.pop_back();

这里的uset不需要回溯,因为我们在每一层使用它,

如果是递归会重新定义,内容被清空不影响判断去重 

此外在加入结果到result数组中时,我们要先判断path.size()>=2,

这也是题目条件之一,要求子序列长度大于等于2

if(path.size()>=2){

        result.push_back(path);

}

组合所有代码,即可得到完整版如下方! 

code

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums,int startindex){if(path.size()>=2){result.push_back(path);}unordered_set<int> uset; // 使用set来对本层元素进行去重for(int i=startindex;i<nums.size();i++){if(!path.empty() && nums[i]<path.back() || uset.find(nums[i])!=uset.end())            {continue;}uset.insert(nums[i]);path.push_back(nums[i]);backtracking(nums,i+1);path.pop_back();}}vector<vector<int>> findSubsequences(vector<int>& nums) {backtracking(nums,0);return result;}
};

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

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

相关文章

Nginx目录结构

Nginx目录结构 ​ Nginx 的安装目录结构可能会因安装方式&#xff08;如使用包管理器、源码编译等&#xff09;和操作系统的不同而有所差异。以下是通过在线安装时&#xff0c;Nginx 默认的目录结构&#xff0c;以及各目录和文件的作用。 yum install nginx查询nginx [rootRo…

2.(vue3.x+vite)使用vue-router

前端技术社区总目录(订阅之前请先查看该博客) 效果预览 路由配置的“/”与“helloWorld”都可以访问到以下内容 http://10.11.0.87:4000/#/ http://10.11.0.87:4000/#/helloWorld 1:安装vue-router npm i vue-router 2:创建router文件 在src的目录下创建router文件夹…

后端返回了 xlsx 文件流,前端怎么下载处理

当后端返回一个 .xlsx 文件流时&#xff0c;前端可以通过 JavaScript 处理这个文件流并触发浏览器下载。 实现步骤 发送请求获取文件流&#xff1a; 使用 fetch 或 axios 等工具向后端发送请求&#xff0c;确保响应类型设置为 blob&#xff08;二进制数据流&#xff09;。 创建…

HTML5拖拽功能教程

HTML5拖拽功能教程 简介 HTML5引入了原生拖放(Drag and Drop)API&#xff0c;使开发者能够轻松实现网页中的拖拽功能&#xff0c;无需依赖第三方库。拖拽功能可以大大提升用户体验&#xff0c;适用于文件上传、列表排序、看板系统等多种交互场景。本教程将带您全面了解HTML拖…

VUE3 路由配置

1.下载 VueRouter 模块 在命令行中输入 yarn add vue-router 2.导⼊相关函数 在自己创建的router/index.js 文件中 import { createRouter, createWebHashHistory } from vue-router 3.创建路由实例 在自己创建的router/index.js 文件中 const theFirstRouter ()>{return…

历史序列影像 Esri的World Imagery Wayback简介

Esri的World Imagery Wayback是一个专注于提供历史卫星影像的在线平台&#xff0c;由全球领先的地理信息系统&#xff08;GIS&#xff09;技术提供商Esri开发。该平台整合了多源卫星影像数据&#xff0c;允许用户回溯特定区域在不同时间点的影像变化&#xff0c;支持时间序列分…

golang结构体与指针类型

结构体与指针类型 指针类型字段 具名字段 举例 package struct_knowledgeimport "fmt"//结构体字段为指针类型 func StructWithPoint(){type Student struct{name *string}var lisa Studentfmt.Printf("赋值前,Student的实例的值%#v\n",lisa)//错误的赋…

NetMizer-日志管理系统-远程命令执行漏洞挖掘

漏洞描述&#xff1a;NetMizer 日志管理系统 cmd.php中存在远程命令执行漏洞&#xff0c;攻击者通过传入 cmd参数即可命令执行 1.fofa搜素语句 title"NetMizer 日志管理系统" 2.漏洞验证 网站页面 验证POC /data/manage/cmd.php?cmdid

Contactile三轴触觉传感器:多维力感赋能机器人抓取

在非结构化环境中&#xff0c;机器人对物体的精准抓取与操作始终面临巨大挑战。传统传感器因无法全面感知触觉参数&#xff08;如三维力、位移、摩擦&#xff09;&#xff0c;难以适应复杂多变的场景。Contactile推出的三轴触觉力传感器&#xff0c;通过仿生设计与创新光学技术…

OpenCV三维解算常用方法C++

如果标定过程是通过OpenCV张正友标定法实现的&#xff0c;得到的内参外参保存在.txt文件中是这样的形式&#xff1a; ① 内参intrinsics.txt&#xff1a; ② 外参extrinsics.txt&#xff1a; 那么可以通过如下方法读取.txt文件获取左右相机内外参&#xff0c;主要包括三维解算…

栈和队列相关知识题目

栈的底层原理 栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;LIFO&#xff09;​的线性数据结构&#xff0c;所有操作&#xff08;如插入、删除&#xff09;仅在栈顶进行。它的底层实现可以是数组或链表&#xff0c;具体取决于编程语言和应用场景。 1.基于数组实…

【实战案例】永洪vividime:精准赋能零售行业,实现数据洞察与业务增长

在零售食品行业变革加速、市场竞争白热化的背景下&#xff0c;XX集团作为休闲食品领域头部企业&#xff0c;面临消费趋势变化、宏观经济承压及业绩增长乏力的多重挑战。为破解增长困境&#xff0c;集团将“收入增长金额”确立为核心战略指标&#xff08;北极星指标&#xff09;…

一些题目记录

别人面经题目记录 https://zhuanlan.zhihu.com/p/32626732052 实现 NMS&#xff0c;七八次&#xff0c;很高频&#xff1b; 实现 MultiHeadSelfAttention&#xff0c;大概 三四次&#xff1b; 用 Numpy 或者 List 实现MLP 的前向和反向&#xff0c;4次&#xff1b; Leetcode …

面试题分享-多线程顺序打印奇偶数

目录 1.题目详情 2.解题思路 2.1.分析题目 2.2.解析思路 3.代码实现 4.运行结果 1.题目详情 昨天刷抖音&#xff0c;遇到一个面试题&#xff0c;描述如下&#xff1a; 请使用两个线程&#xff0c;分别顺序交替打印奇数和偶数&#xff0c;直到10为止。例如有两个线程&#…

模型 杜根定律

系列文章分享模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。信心>能力、行动导向、未来时态。 1 杜根定律的应用 1.1 公共政策博弈——底特律市长杜根的保险改革攻坚战 核心挑战&#xff1a;底特律市长Mike Duggan面临汽车保险费率畸高导致居民陷入贫困循环的…

关于在vscode中的Linux 0.11 应用程序项目的生成和运行

首先我们需要需要查看镜像文件 查看软盘镜像文件 floppyb.img 中的内容 在 VSCode 的“Terminal”菜单中选择“Run Build Task...”&#xff0c;会在 VSCode 的顶部中间位置弹出一个 可以执行的 Task 列表&#xff0c;选择其中的“打开 floppyb.img”后会使用 Floppy Editor …

使用CSS3实现炫酷的3D视差滚动效果

使用CSS3实现炫酷的3D视差滚动效果 这里写目录标题 使用CSS3实现炫酷的3D视差滚动效果项目概述核心技术实现1. 3D空间的创建2. 视差层级设置3. 动画效果实现流星动画月亮发光效果 技术难点与解决方案1. 层级重叠问题2. 性能优化3. 响应式适配 开发心得总结 项目概述 在这个项目…

作业12 (2023-05-15 指针概念)

第1题/共11题【单选题】 关于指针的概念,错误的是:( ) A.指针变量是用来存放地址的变量 B.指针变量中存的有效地址可以唯一指向内存中的一块区域 C.野指针也可以正常使用 D.局部指针变量不初始化就是野指针 回答正确 答案解析: A:正确,指针变量中存储的是一个地址,指…

【ESP32S3】esp32获取串口数据并通过http上传到前端

通过前面的学习&#xff08;前面没发过&#xff0c;因为其实就是跑它的demo&#xff09;了解到串口配置以及开启线程实现功能的工作流程&#xff0c;与此同时还有esp32作为STA节点&#xff0c;将数据通过http发送到服务器。 将这两者联合 其实是可以得到一个&#xff1a;esp32获…

《鸿蒙携手AI:解锁智慧出行底层逻辑》

在科技飞速发展的当下&#xff0c;智慧出行成为人们对未来交通的美好期许&#xff0c;而鸿蒙系统与人工智能的深度融合&#xff0c;正为这一愿景的实现提供强大助力。从技术原理角度深入剖析&#xff0c;鸿蒙系统究竟如何支撑人工智能在智慧出行场景中的应用呢&#xff1f;这背…