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/10/16 7:47:36 阅读更多 →
n8n与Dify搭建智能Agent工作流实战指南

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

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

2026/10/16 1:55:14 阅读更多 →
Bash脚本自动化:从基础到实战技巧

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

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

2026/10/16 13:58:58 阅读更多 →

最新新闻

Halcon与C#混合编程实战:从环境配置到部署的完整指南

Halcon与C#混合编程实战:从环境配置到部署的完整指南

干机器视觉这行的朋友,应该都有过这种经历:算法在HDevelop里跑得飞起,模板匹配、Blob分析、边缘提取一堆算子拼在一起,处理效果调得明明白白,可一到要把它变成真正能交付的软件,问题就全冒出来了。界面要有…

2026/10/16 18:58:52 阅读更多 →
善付通支付接入实战:从报文规范到联调对账全解析

善付通支付接入实战:从报文规范到联调对账全解析

简介:《建设银行善付通支付结算接入文档》是建行善融商务平台中善付通服务的官方对接指南,面向企业后端开发、系统集成与运维人员,旨在解决供应链上下游企业在订单协同、在线收付款和自动化对账中遇到的流程分散、人工核对量大等痛点。文档共…

2026/10/16 18:58:52 阅读更多 →
DeepSeek API调用全流程详解:从密钥申请到工程化集成

DeepSeek API调用全流程详解:从密钥申请到工程化集成

简介:面向软件工程师、科研人员及AI服务开发者,这份DeepSeek API调用指南系统梳理了从权限申请到项目集成的完整工作流。内容涵盖访问权限申请与密钥获取、官方文档解读、开发环境与编程语言选择、依赖库安装、请求头与参数构造、响应解析及测试调试等环…

2026/10/16 18:58:52 阅读更多 →
视觉问答VQA综述:从数据集、算法演进到评估与落地挑战

视觉问答VQA综述:从数据集、算法演进到评估与落地挑战

前段时间我在帮某团队调试一套多模态内容整理工具,对方提了一个看起来特别基础的问题:“图片里有两个小孩和一条狗,狗在孩子前面还是后面?”我第一反应是目标检测就能搞定,真正动手做才发现,这要拆成好几段…

2026/10/16 18:58:52 阅读更多 →
建筑物损坏缺陷识别YOLO数据集:2400张增强数据训练避坑指南

建筑物损坏缺陷识别YOLO数据集:2400张增强数据训练避坑指南

简介:建筑物损坏缺陷识别检测YOLO数据集面向计算机视觉学习者、结构安全监测研究人员及智能检测系统开发者,主要用于解决裂缝、外露钢筋、剥落三类建筑物缺陷的实时定位与识别问题,可适用于施工现场巡检、老旧建筑安全评估等场景。压缩包内含…

2026/10/16 18:58:52 阅读更多 →
蓝屏代码0x0000001E怎么查?从停机码到内存转储的系统排查指南

蓝屏代码0x0000001E怎么查?从停机码到内存转储的系统排查指南

简介:《windows蓝屏代码查询》是一份面向Windows系统维护人员、电脑维修从业者及普通用户的蓝屏故障速查文档。内容从蓝屏界面入手,详细拆解STOP停机码(Stop Code)、错误名称及括号内四个参数的实际含义,帮助读者理解崩…

2026/10/16 18:57:50 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →