【LeetCode 热题 100】46. 全排列——回溯

Problem: 46. 全排列

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N * N!)
    • 空间复杂度:O(N)

整体思路

这段代码旨在解决一个经典的组合数学问题:全排列 (Permutations)。给定一个不含重复数字的数组 nums,它需要找出其所有可能的全排列,并返回一个包含这些排列的列表。

该算法采用的核心方法是 回溯法(Backtracking),这是一种通过 深度优先搜索(DFS) 来系统地探索所有可能解的搜索策略。

算法的整体思路可以分解为以下步骤:

  1. 逐位构建排列

    • 算法将生成一个排列的过程看作是逐个“填空”的过程。它定义了一个 dfs(i, ...) 函数,其核心任务是确定排列中第 i 个位置应该填入哪个数字。
  2. 状态维护

    • 为了辅助构建过程,算法使用了两个关键的数据结构:
      • List<Integer> path:用于存储当前正在构建的排列。
      • boolean[] onPath:一个与原数组 nums 等长的布尔数组,用作“访问标记”。onPath[j] = true 表示 nums[j] 这个数字已经被放入了当前的 path 中,不能再被使用。
  3. 递归与回溯的核心逻辑

    • dfs 函数从第 0 位开始 (i=0)。在为第 i 位选择数字时,它会遍历整个原始数组 nums
    • 对于 nums 中的每一个数字 nums[j],它会检查该数字是否已被使用(if (!onPath[j]))。
    • 选择 (Choose):如果 nums[j] 未被使用,就做出选择:
      a. 将 nums[j] 放入当前排列的第 i 位:path.set(i, nums[j])
      b. 将 nums[j] 标记为已使用:onPath[j] = true
    • 探索 (Explore):做出选择后,递归地调用 dfs(i + 1, ...),去解决下一个子问题——填充第 i+1 位。
    • 撤销选择 (Unchoose / Backtrack):当对 i+1 位的探索(即 dfs(i + 1, ...) 调用)返回后,必须撤销刚才的选择。这是回溯法的精髓。
      a. 将 nums[j] 标记为未使用:onPath[j] = false
      b. 这样,在下一次循环中,nums[j] 就可以被用来填充其他位置,从而形成不同的排列。
  4. 递归终止条件

    • i 的值等于数组长度 n 时(if (i == n)),意味着排列的所有 n 个位置都已经被成功填满。
    • 此时,一个完整的排列就构建好了(存储在 path 中)。
    • path 的一个深拷贝new ArrayList<>(path))添加到最终的结果列表 ans 中。必须使用拷贝,因为 path 本身会在回溯过程中被不断修改。

通过这个“选择-探索-撤销”的循环,算法能够不重不漏地遍历所有可能的排列组合。

完整代码

class Solution {/*** 计算给定数组的全排列。* @param nums 不含重复数字的整数数组* @return 包含所有全排列的列表*/public List<List<Integer>> permute(int[] nums) {int n = nums.length;// ans: 最终的结果列表List<List<Integer>> ans = new ArrayList<>();// path: 用于存储当前正在构建的单个排列路径// Arrays.asList(new Integer[n]) 创建一个固定大小的、由null填充的List,便于后续使用 set 方法List<Integer> path = Arrays.asList(new Integer[n]);// onPath: 标记数组,onPath[j]为true表示nums[j]已在当前path中boolean[] onPath = new boolean[n];// 从第 0 个位置开始进行深度优先搜索dfs(0, nums, ans, path, onPath);return ans;}/*** 深度优先搜索(回溯)辅助函数。* @param i 当前需要填充的排列位置的索引* @param nums 原始输入数组* @param ans 结果列表* @param path 当前构建的排列* @param onPath 标记数组*/private void dfs(int i, int[] nums, List<List<Integer>> ans, List<Integer> path, boolean[] onPath) {int n = nums.length;// 递归终止条件:当 i 等于 n 时,说明所有位置都已填满,一个完整的排列已生成if (i == n) {// 将当前路径的一个深拷贝加入到结果列表中// 必须是深拷贝,因为 path 会在回溯过程中被修改ans.add(new ArrayList<>(path));return; // 结束当前递归分支}// 遍历所有可用的数字,尝试将其放入第 i 个位置for (int j = 0; j < n; j++) {// 如果 nums[j] 还未在当前路径中使用过if (!onPath[j]) {// 选择:将 nums[j] 放入第 i 个位置path.set(i, nums[j]);// 标记 nums[j] 为已使用onPath[j] = true;// 探索:递归地去填充下一个位置 (i + 1)dfs(i + 1, nums, ans, path, onPath);// 撤销选择(回溯):将 nums[j] 标记为未使用,// 这样它就可以在其他分支中被用于其他位置。这是回溯法的核心。onPath[j] = false;}}}
}

时空复杂度

时间复杂度:O(N * N!)

  1. 排列数量:对于一个包含 N 个不同元素的集合,其全排列的数量是 N! (N的阶乘)。
  2. 构建每个排列的成本
    • 算法的搜索过程可以看作是在一棵“排列树”上进行DFS。这棵树有 N! 个叶子节点,每个叶子节点代表一个完整的排列。
    • 从根节点到任意一个叶子节点的路径长度为 N
    • 当到达一个叶子节点时(即 i == n),需要执行 new ArrayList<>(path) 操作,这是一个 O(N) 的操作,用于复制当前排列。
  3. 综合分析
    • 总的时间复杂度约等于 (叶子节点数量 * 到达叶子节点的成本) + (非叶子节点的计算成本)。
    • 非叶子节点的总数也与 N! 相关。
    • 一个更精确的视角是,总共有 N! 个排列,每个排列的生成和复制都需要 O(N) 的时间。因此,总时间复杂度为 O(N * N!)

空间复杂度:O(N)

  1. 主要存储开销:我们分析的是额外辅助空间,不包括存储最终结果的 ans 列表(否则空间将是 O(N * N!))。
    • List<Integer> path: 用于存储当前路径,其大小为 N。空间复杂度为 O(N)
    • boolean[] onPath: 标记数组,其大小为 N。空间复杂度为 O(N)
    • 递归调用栈dfs 函数的最大递归深度为 N(从 i=0i=n)。因此,递归栈所占用的空间为 O(N)

综合分析
算法所需的额外辅助空间由 pathonPath 和递归栈深度共同决定。它们都是 O(N) 级别的。因此,总的辅助空间复杂度为 O(N)

参考灵神

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

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

相关文章

AXI接口学习

amba总线的发展axi协议是两个接口之间的点对点的协议&#xff0c;主要是有5个通道。主机在写地址&#xff08;AW&#xff09;通道上发送地址&#xff0c;并在写数据&#xff08;W&#xff09;通道上将数据传输到从机。从机将接收到的数据写入指定地址空间。从机完成写操作&…

Validation - Spring Boot项目中参数检验的利器

Validation - Spring Boot项目中参数检验的利器 什么是Validation Sping Boot官方原文&#xff1a;When it comes to validating user input, Spring Boot provides strong support for this common, yet critical, task straight out of the box.Although Spring Boot support…

云服务器VS虚拟主机:如何抉择?

开篇引入在当今数字化浪潮中&#xff0c;无论是个人站长想要搭建独具风格的博客&#xff0c;展示自己的生活感悟与专业见解&#xff1b;还是中小企业期望构建官方网站&#xff0c;拓展线上业务版图&#xff0c;提升品牌知名度&#xff1b;亦或是大型互联网企业筹备高并发的电商…

不同相机CMOS噪点对荧光计算的影响

摘要&#xff1a;荧光成像是生物医学、材料科学等领域的重要研究手段&#xff0c;其成像质量高度依赖传感器噪声特性。本文系统分析CMOS传感器噪声类型及其对荧光信号计算的影响机制&#xff0c;结合实验数据探讨不同CMOS架构的噪声表现差异&#xff0c;提出针对性优化策略。研…

docker 常见命令使用记录

1. swarm 集群 1. 集群创建 # 创建集群管理节点&#xff0c; --advertise-addr 指定节点管理通信地址&#xff0c;--data-path-addr 指定容器通信地址 docker swarm init --advertise-addr 1.14.138.35 --data-path-addr 1.14.138.35# --advertise-addr 指明当前work节点的…

KRaft 角色状态设计模式:从状态理解 Raft

这些状态类是 Raft 协议行为的核心载体。它们包含转移逻辑 和 节点在特定状态下的所有行为和数据。QuorumState它是 KRaft 客户端实现中状态管理的核心&#xff0c;扮演着“状态机上下文&#xff08;Context&#xff09;”和“状态转换协调者”的关键角色。QuorumState 是整个 …

Linux的磁盘存储管理实操——(上)

一、Linux的设备文件分类 Linux的设备文件分类1、在Linux系统中设备文件是用来与外接交互的接口&#xff0c;它将内核中的硬件设备与文件系统关联起来&#xff0c;让用户可以像操作普通文件一样来操作硬件设备&#xff0c;同时也为开发者提供了方便而强大的应用程序接口。 2、L…

内核bpf的实现原理

bpftrace能帮我们干什么&#xff1f;1、统计 tcp连接的生命时长、2、统计mysql执行一条sql语句的时间3、统计redis执行命令的时间、 4、对文件进行一次读或者写的时间。 常用命令&#xff1a; bpftrace -e Begin { printf("hello\n"); } bpftrace -l *enter_accep…

前端npm配置Nexus为基础仓库

步骤&#xff1a; 一、Nexus仓库配置 新增npm仓库,具体详解见 Nexus私有仓库配置&#xff0c;解释 注&#xff1a;Nexus的版本需要至少3.38以上&#xff0c;不然会出现npm install 时npm的审计功能报错&#xff0c;导致install失败。虽然在3.38以后不会报400错误&#xff0c…

数据结构 之 【排序】(直接插入排序、希尔排序)

目录 1.直接插入排序 1.1直接插入排序的思想 1.2直接插入排序的代码逻辑&#xff1a; 1.3 直接插入排序图解 1.4单趟排序代码(单个元素的排序逻辑) 1.5完整排序代码 1.6直接插入排序的时间复杂度与空间复杂度 1.7直接插入排序的优势 2.希尔排序(缩小增量排序) 2.1…

Laravel 后台登录 403 Forbidden 错误深度解决方案-优雅草卓伊凡|泡泡龙

Laravel 后台登录 403 Forbidden 错误深度解决方案-优雅草卓伊凡|泡泡龙一顿操作猛如虎&#xff0c;一看结果250&#xff0c;必须记录&#xff0c;必须记录&#xff0c;&#xff01;今天弄了很久关于我们2023年的产品系统蜻蜓T会议系统专业版&#xff0c;然后终于搞好了密码也重…

Newline全场景方案闪耀2025中国智慧生活大会

7月15日 — 16日&#xff0c;由中国电子视像行业协会等权威机构指导的2025 CIC中国智慧生活大会在京召开。Newline作为视像协会PID分会副会长单位携全场景智慧办公解决方案亮相&#xff0c;首席营销官李宇鹏受邀出席领袖圆桌环节&#xff0c;与腾讯云、京东方、创维、TCL、小猿…

Edge浏览器地址栏默认搜索引擎设置指南

前言 Microsoft Edge 浏览器允许用户自定义地址栏默认搜索引擎&#xff0c;只是设置入口隐藏比较深&#xff0c;以版本 137.0.3296.83 (正式版本) (64 位)为例详细记录设置地址栏默认搜索引擎步骤&#xff1a; Edge 设置默认搜索引擎步骤 通过设置界面修改 打开Edge设置&#x…

Python eval函数详解 - 用法、风险与安全替代方案

Python eval函数详解 - 用法、风险与安全替代方案在Python中&#xff0c;eval() 是一个内置函数&#xff0c;用于解析并执行传入的字符串形式的表达式。它能够将字符串动态地转换为有效的Python代码并运行。虽然 eval() 功能强大&#xff0c;但其使用也伴随着潜在的安全风险。本…

Webpack5 新特性与详细配置指南

一、Webpack5 新特性 内置 Asset Modules&#xff08;资源模块&#xff09; 替代 file-loader、url-loader、raw-loader 等&#xff0c;统一资源处理方式。四种类型&#xff1a;asset/resource&#xff1a;导出文件 URL&#xff08;等同 file-loader&#xff09;。asset/inli…

笼子在寻找一只鸟:解读生活的隐形陷阱

想象一个闪闪发光的笼子&#xff0c;敞开着门&#xff0c;在世界中游荡&#xff0c;寻找一只鸟儿。这画面是不是有点奇怪&#xff1f;这是卡夫卡的格言“一个笼子在寻找一只鸟”带给我们的奇思妙想。通常&#xff0c;鸟儿自由翱翔&#xff0c;笼子静静等待&#xff0c;但卡夫卡…

低空经济展 | 约克科技携小型化测试设备亮相2025深圳eVTOL展

全球低空经济与eVTOL产业盛会——2025深圳eVTOL展&#xff0c;将于2025年9月23日至25日在深圳坪山燕子湖国际会展中心盛大启幕&#xff01; 本届展会以“低空经济eVTOL航空应急救援商载大型无人运输机”为核心&#xff0c;预计汇聚200位发言嘉宾、500家顶尖展商及15,000位专业观…

数学专业转行做大数据容易吗?需要补什么?

高考志愿选择数学专业是一个面向未来的决定。数学作为基础学科&#xff0c;其严谨的逻辑训练和抽象思维能力培养&#xff0c;为后续专业发展提供了广泛的可能性。在数字化时代背景下&#xff0c;数学专业毕业生在数据科学、人工智能等领域的竞争优势明显。大学期间推荐考CDA数据…

物联网系统中-设备管理定义方法

物联网系统中的设备管理是指对联网物理设备进行全生命周期监控、配置、维护和优化的系统性过程。它涵盖了从设备接入到退役的各个环节&#xff0c;是物联网平台的核心能力&#xff0c;确保设备安全、稳定、高效地运行并产生价值。 以下是设备管理的详细定义与核心组成部分&…

java和ptyhon对比

&#x1f4dd; ​1. 语言特性对比​​维度​​Java​​Python​​语法风格​静态类型&#xff0c;需显式声明变量类型&#xff1b;代码冗长&#xff08;需分号、大括号&#xff09;动态类型&#xff0c;变量类型自动推断&#xff1b;简洁&#xff08;缩进代替大括号&#xff0c…