Hot 100 --- 全排列
本文概览本文以LeetCode题目全排列为例讲解回溯法的核心思路——已选择/未选择的划分visited数组维护顺序回溯就是撤销选择换下一个一、题目二、题目分析题目要求给定一个没有重复数字的数组返回所有可能的全排列全排列其实是初高中常遇到的数学题——n 个元素能排成多少个序列答案是 n!。过程是这样的第1次选择从 n 个元素里选 1 个 → n 种 第2次选择从剩下的 n-1 个里选 1 个 → n-1 种 第3次选择从剩下的 n-2 个里选 1 个 → n-2 种 ... 第n次选择只剩 1 个没得选 → 1 种 总排列数 n × (n-1 × (n-2 × ... × 1)) n!这题的难点不是思路而是怎么不重不漏地遍历完所有排列。如果随便选必然会有重复。所以必须按某种顺序系统地遍历这就需要回溯法思路概览classSolution{publicListListIntegerpermute(int[]nums){// 结果列表ListListIntegerresnewArrayList();if(nums.length0){returnres;}// 访问数组boolean[]visitednewboolean[nums.length];// 递归函数backtrack(res,visited,nums,newArrayList());returnres;}privatevoidbacktrack(ListListIntegerres,boolean[]visited,int[]nums,ArrayListIntegerpath){// 递归出口if(path.size()nums.length){res.add(newArrayList(path));return;}for(inti0;inums.length;i){// 剪枝if(visited[i]){continue;}// 标记访问过visited[i]true;// 添加到当前路径path.add(nums[i]);// 递归调用backtrack(res,visited,nums,path);// 回溯visited[i]false;// 从当前路径中移除path.removeLast();}}}思路简要说明已选择 / 未选择用 path 记录已选的元素用 visited 数组记录每个元素有没有被选过false 没选过。每轮从 i0 扫到末尾跳过选过的选没选过的回溯 撤销选择换下一个递归回来后撤销当前选择visited 设回 falsepath 移除最后一个for 循环 i 自动选下一个元素。这就实现了选完一个换下一个试试三、思路详解第一步已选择 / 未选择的划分回忆前面做过的题——无论 DFS 还是 BFS我们都需要知道已经处理了什么还没处理什么。全排列也一样可以把数组分成两部分已选择已经加入排列的元素用 path 列表记录未选择还没加入排列的元素用 visited 数组标记false 表示未选择以 nums [1, 2, 3] 为例 初始状态 已选择 path [] 未选择 visited [false, false, false] → 1, 2, 3 都可选 选了 1 之后 已选择 path [1] 未选择 visited [true, false, false] → 2, 3 可选 再选了 2 之后 已选择 path [1, 2] 未选择 visited [true, true, false] → 只有 3 可选第二步怎么保证不重不漏这是这题的核心问题。如果随便选比如先选 2 再选 1和先选 1 再选 2可能会产生重复的遍历路径解决办法很简单每一轮都从 i0 开始扫描遇到选过的就跳过选第一个没选过的。因为 for 循环永远从 0 开始选过的元素会被if (visited[i]) continue跳过没选过的元素会按数组下标顺序依次被选中nums [1, 2, 3]假设 1 已经选过了 i0: visited[0]true → 跳过 i1: visited[1]false → 选 2 i2: visited[2]false → 选 3 没选过的 2、3 会按数组顺序被选到不会乱每次都是按固定顺序选不可能产生重复第三步回溯是什么回溯就是撤销当前选择换下一个试试用 nums [1, 2, 3] 举例手动模拟一遍全过程第一轮全选第一个 选 1 → path [1] 选 2 → path [1, 2] 选 3 → path [1, 2, 3] ✓ 第1个排列 回溯撤销 3path [1, 2] 没有其他可选了 回溯撤销 2path [1] 选 3 → path [1, 3] 选 2 → path [1, 3, 2] ✓ 第2个排列 回溯撤销 2path [1, 3] 没有其他可选了 回溯撤销 3path [1] 没有其他可选了 回溯撤销 1path [] 第二轮从倒数第二个开始换 选 2 → path [2] 选 1 → path [2, 1] 选 3 → path [2, 1, 3] ✓ 第3个排列 ... 选 3 → path [2, 3] 选 1 → path [2, 3, 1] ✓ 第4个排列 ... 回溯撤销 2path [] 第三轮换到第一个位置的第三个元素 选 3 → path [3] 选 1 → path [3, 1] 选 2 → path [3, 1, 2] ✓ 第5个排列 ... 选 2 → path [3, 2] 选 1 → path [3, 2, 1] ✓ 第6个排列 ... 回溯撤销 3path []6 个排列正好是 3! 6。观察整个过程第一轮全选第一个得到 [1,2,3]然后从倒数第二个开始回溯换一个选择得到 [1,3,2]再往上一层回溯从倒数第三个开始换选第二个元素 2然后重复第一轮第二轮的操作再从倒数第三个换到第三个元素 3重复操作这就是回溯的本质——从最深处开始撤销换一个选择换完后继续往下走这一层换完了就退到上一层再换第四步代码怎么对应这个过程for(inti0;inums.length;i){if(visited[i])continue;// ① 跳过已选的visited[i]true;// ② 标记选择path.add(nums[i]);// ③ 加入路径backtrack(...);// ④ 往下递归visited[i]false;// ⑤ 回溯撤销标记path.removeLast();// ⑥ 回溯移出路径}①②③选择当前元素④带着这个选择往下走处理剩余元素⑤⑥递归回来后撤销选择for 循环 i 自动选下一个for 循环就是遍历所有可选元素回溯就是选完了换下一个。不需要手动控制从倒数第几个开始换——for 循环 递归自然就实现了这个逻辑第五步递归出口if(path.size()nums.length){res.add(newArrayList(path));return;}当 path 的长度等于 nums 的长度时说明所有元素都选完了这是一个完整的排列。注意要用new ArrayList(path)创建副本——如果直接 add(path)后续回溯修改 path 会影响已经存入的结果第六步完整执行过程图解以 nums [1, 2, 3] 为例用缩进表示递归深度path [] visited [F, F, F] i0: 选 1 → path [1] visited [T, F, F] i0: 跳过已访问 i1: 选 2 → path [1,2] visited [T, T, F] i0: 跳过 i1: 跳过 i2: 选 3 → path [1,2,3] ✓ 加入结果 回溯path [1,2] visited [T, T, F] 回溯path [1] visited [T, F, F] i2: 选 3 → path [1,3] visited [T, F, T] i0: 跳过 i1: 选 2 → path [1,3,2] ✓ 加入结果 回溯path [1,3] 回溯path [1] 回溯path [] visited [F, F, F] i1: 选 2 → path [2] visited [F, T, F] i0: 选 1 → path [2,1] visited [T, T, F] i2: 选 3 → path [2,1,3] ✓ 加入结果 回溯... i2: 选 3 → path [2,3] visited [F, T, T] i0: 选 1 → path [2,3,1] ✓ 加入结果 回溯... 回溯path [] i2: 选 3 → path [3] visited [F, F, T] i0: 选 1 → path [3,1] visited [T, F, T] i1: 选 2 → path [3,1,2] ✓ 加入结果 回溯... i1: 选 2 → path [3,2] visited [F, T, T] i0: 选 1 → path [3,2,1] ✓ 加入结果 回溯... 回溯path []最终结果[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]共 6 个复杂度分析时间复杂度O(n × n!)共 n! 个排列每个排列需要 O(n) 时间复制到结果空间复杂度O(n)递归深度最大为 nvisited 数组和 path 都是 O(n)

相关新闻

抖音无水印批量下载终极指南:douyin-downloader免费工具完整使用教程

抖音无水印批量下载终极指南:douyin-downloader免费工具完整使用教程

抖音无水印批量下载终极指南:douyin-downloader免费工具完整使用教程 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser …

2026/7/27 6:50:11 阅读更多 →
n8n与Dify搭建智能Agent工作流实战指南

n8n与Dify搭建智能Agent工作流实战指南

1. 为什么选择n8n和Dify搭建Agent工作流在自动化工具百花齐放的今天,n8n和Dify这两个开源平台凭借独特的优势成为了搭建Agent工作流的热门选择。n8n作为一款可视化工作流自动化工具,其节点式操作界面让非技术人员也能快速上手,而Dify则专注于…

2026/7/27 6:49:10 阅读更多 →
Bash脚本自动化:从基础到实战技巧

Bash脚本自动化:从基础到实战技巧

1. 为什么需要Bash脚本自动化第一次在服务器上手动处理日志文件时,我花了整整三小时重复执行相同的grep和awk命令。当第二天同样的任务又出现时,我意识到必须改变工作方式了。Bash脚本正是为解决这类重复劳动而生,它能把繁琐的命令序列封装成…

2026/7/27 6:49:10 阅读更多 →

最新新闻

OpenClaw AI框架安全加固实战:从RBAC权限到生产环境部署

OpenClaw AI框架安全加固实战:从RBAC权限到生产环境部署

1. 项目概述:为什么OpenClaw的安全配置与权限管理是“必修课”?最近在折腾OpenClaw,一个基于FastAPI和LangChain的AI智能体开发框架,功能确实强大,能搞多代理协同、记忆管理,还能对接各种大模型。但玩着玩着…

2026/7/27 7:02:16 阅读更多 →
AI-WEB-1.0靶机渗透实战:从信息收集到权限提升完整指南

AI-WEB-1.0靶机渗透实战:从信息收集到权限提升完整指南

1. 项目概述与靶机环境搭建 AI-WEB-1.0靶机是近年来在安全学习圈子里比较热门的一款模拟靶机,它集成了多种常见的Web应用漏洞和系统层面的安全弱点,非常适合用来练习从外部信息收集到最终获取系统最高权限的完整渗透测试流程。很多朋友在初次接触这类综合…

2026/7/27 7:02:16 阅读更多 →
BBWEYY行业模板与开放生态能力测评——基于行业适配、多端复用、第三方连接与扩展性的分析,含零代码SAAS、AI编程、源码定制交付

BBWEYY行业模板与开放生态能力测评——基于行业适配、多端复用、第三方连接与扩展性的分析,含零代码SAAS、AI编程、源码定制交付

BBWEYY行业模板与开放生态能力测评 ——基于行业适配、多端复用、第三方连接与扩展性的分析 摘要 行业模板能够提高上线速度,但企业长期使用还取决于模板是否匹配业务流程、能否跨端复用以及是否支持第三方系统连接。本文对BBWEYY的行业模板体系、标准商城与高端…

2026/7/27 7:02:16 阅读更多 →
图像掩码解码

图像掩码解码

图像掩码解码 一、技术背景 YOLOv8/YOLO11实例分割模型采用了一种高效的掩码表示方式:原型掩码(Prototype Masks) 掩码系数(Mask Coefficients)。这种设计将掩码表示分解为两部分:一组与类别无关的原型掩码…

2026/7/27 7:02:16 阅读更多 →
Windows下C++开发环境搭建:从MinGW-w64到VS Code的完整指南

Windows下C++开发环境搭建:从MinGW-w64到VS Code的完整指南

1. 项目概述:为什么从环境搭建开始?很多新手朋友一上来就想写个“Hello World”,结果卡在了第一步——环境没配好。我见过太多人,兴致勃勃地打开教程,下载了Visual Studio,结果被几个G的安装包和一堆看不懂…

2026/7/27 7:02:16 阅读更多 →
跨境独立站支付成功率的影响因素与优化机制研究——基于BBWEYY支付体系的分析——支付方式、结账体验与风险控制的协同治理,含零代码SAAS、AI编程、源码定制交付

跨境独立站支付成功率的影响因素与优化机制研究——基于BBWEYY支付体系的分析——支付方式、结账体验与风险控制的协同治理,含零代码SAAS、AI编程、源码定制交付

跨境独立站支付成功率的影响因素与优化机制研究——基于BBWEYY支付体系的分析——支付方式、结账体验与风险控制的协同治理摘 要支付成功率直接决定跨境独立站流量能否转化为收入。本文从支付方式覆盖、结账步骤、币种展示、风控审核和失败恢复等维度分析支付成功率&#xff0c…

2026/7/27 7:01:15 阅读更多 →

日新闻

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:54 阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻