用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录
- 一、题目介绍
- 二、递归思路详解:从决策树开始理解
- 三、解法一:二叉决策树 DFS
- 四、解法二:组合式回溯写法(推荐)
- 五、解法对比
递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的问题,比如树的遍历、组合问题、回溯搜索等。
今天,我们以 LeetCode 第 78 题「子集(Subsets)」为例,带大家深入理解递归的思路、实现细节以及不同写法的差异。
一、题目介绍
题目链接: 78. 子集 - LeetCode
题目描述:
给定一个整数数组 nums,返回该数组所有可能的子集(幂集)。
示例:
输入: nums = [1,2,3]
输出: [[], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]]
二、递归思路详解:从决策树开始理解
我们用递归的方式去“做决策”——对每个元素,都面临两个选择:
- 选择它
- 不选择它
这种决策结构,其实就像是一棵二叉树:
每一个节点都有两个分支,一个是“我选了当前元素”,另一个是“我跳过当前元素”。
举例说明
以 nums = [1, 2]
为例,整个决策过程如下所示:
[]/ \[1] []/ \ \[1,2] [1] [2]
每一条路径就是一个子集的构建过程:
[]
:什么都不选[1]
:只选第一个[1,2]
:全选[2]
:只选第二个
最终收集所有路径,就是所有的子集
用语言描述递归过程:
- 从位置
0
开始:- 选
nums[0]
,进入下一层递归 - 选
nums[1]
,递归到尽头,保存[1,2]
- 不选
nums[1]
,保存[1]
- 选
- 不选
nums[0]
- 选
nums[1]
,保存[2]
- 不选
nums[1]
,保存[]
- 选
这样,我们就得到了所有子集。
三、解法一:二叉决策树 DFS
解法思路
每次递归考虑一个元素,选或不选。
当走到数组末尾时,当前构建的路径就是一个合法的子集。
class Solution
{vector<vector<int>> ret; // 存放结果集vector<int> path; // 当前构建的子集路径
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums, 0); // 从索引 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);}
};
四、解法二:组合式回溯写法(推荐)
思路核心
我们从当前下标 pos
开始向后遍历,每次选一个元素加入 path
,递归处理后续子集,不再考虑当前之前的元素,避免重复。
这种方式更像是“组合问题”的模板写法。
决策过程
- 每进入递归一次,就把当前 path 加入结果集
- 然后,从当前位置
pos
开始遍历,尝试将每个元素加入path
,并递归后续 - 回溯:递归返回后,需要把最后加入的元素移除,恢复现场
举例说明:
[]┌───────────────┼────────────────┐[1] [2] [3]/ \ / \ \[1,2] [1,3] [2,3] [3]| | |[1,2,3] [1,3] [2,3]
用语言描述过程:
从 pos = 0
开始:
- 先将空集
[]
加入结果集。 - 遍历索引 0~2:
- 选择
nums[0]=1
,路径变为[1]
- 继续从
pos=1
开始遍历:- 选
2
->[1,2]
- 选
3
->[1,2,3]
- 选
- 回溯到 [1]
- 选
3
->[1,3]
- 选
- 继续从
- 回溯回到
[]
- 选
2
->[2]
- 选
3
->[2,3]
- 选
- 回溯回到
[]
- 选
3
->[3]
每一步都把当前的路径保存下来,形成最终的子集集合。
- 选
- 选择
代码实现
class Solution
{vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums, 0); // 从第 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(); // 回溯,移除当前元素}}
};
优点分析
- 不需要写递归出口,利用 for 循环自动控制终止条件
- 结构上类似「组合问题」的回溯模板
为什么说它更像‘组合问题’?
因为组合问题也遵循一个核心原则:
- 每次只能向后选元素,不能回头,以防止重复。
比如要从 [1,2,3] 中选出长度为 2 的组合,这种“向后递归 + 回溯”的结构是最自然的选择。
五、解法对比
比较维度 | 解法一(选/不选) | 解法二(组合式回溯) |
---|---|---|
决策方式 | 二分支:选 or 不选 | 枚举所有起点及其后续路径 |
是否需要出口判断 | 是(pos == nums.size() ) | 否,for 控制终止 |
可读性 | 模拟决策树,结构清晰 | 更接近组合枚举的写法 |
常见用途 | 子集、排列、二叉树类问题 | 子集、组合、N 皇后等问题 |
相关文章:
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...

C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...

CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...

相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...

解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...

Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...

PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...

【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...

Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...