当前位置: 首页 > news >正文

【Leetcode hot 100】46.全排列

问题链接

46.全排列

问题描述

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

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

问题解答

核心思路

全排列的本质是穷举所有元素的不同顺序组合,由于需要“尝试-回溯-再尝试”的逻辑,因此适合用「回溯算法」解决。核心思想是:

  1. 选择元素:从数组中选一个未使用过的元素,加入当前排列路径。
  2. 递归探索:基于当前选择,继续选下一个未使用的元素,直到路径长度等于数组长度(即生成一个完整排列)。
  3. 回溯撤销:递归返回后,撤销上一步的选择(移除路径最后一个元素、标记元素为未使用),继续尝试其他可能性。

Java 代码

import java.util.ArrayList;
import java.util.List;class Solution {// 结果集:存储所有完整排列private List<List<Integer>> result = new ArrayList<>();// 路径:存储当前正在构建的排列private List<Integer> path = new ArrayList<>();public List<List<Integer>> permute(int[] nums) {// used数组:标记nums中哪些元素已被选入当前路径(避免重复选择)boolean[] used = new boolean[nums.length];// 启动回溯backtrack(nums, used);return result;}/*** 回溯函数* @param nums 原始数组(固定不变)* @param used 标记元素使用状态的数组*/private void backtrack(int[] nums, boolean[] used) {// 终止条件:当前路径长度 == 数组长度 → 生成一个完整排列if (path.size() == nums.length) {// 注意:需new ArrayList<>(path),避免后续修改path影响结果(path是引用类型)result.add(new ArrayList<>(path));return;}// 遍历数组:尝试选择每个未使用的元素for (int i = 0; i < nums.length; i++) {// 跳过已使用的元素if (used[i]) {continue;}// 1. 选择当前元素:标记为已使用,加入路径used[i] = true;path.add(nums[i]);// 2. 递归:基于当前选择,继续构建下一层路径backtrack(nums, used);// 3. 回溯:撤销上一步选择(恢复状态,供下一次循环尝试其他元素)path.remove(path.size() - 1); // 移除路径最后一个元素used[i] = false; // 标记为未使用}}
}

代码关键部分解释

  1. 数据结构作用

    • result:最终返回的所有排列集合,每个元素是一个完整的排列(List<Integer>)。
    • path:临时存储当前正在构建的排列,比如从[1][1,2]再到[1,2,3]
    • used:布尔数组,长度与nums一致,used[i] = true表示nums[i]已被选入当前path,避免重复选择。
  2. 回溯函数流程(以nums = [1,2,3]为例)

    • 第一次调用backtrackpath为空,遍历i=0nums[0]=1未使用),标记used[0]=truepath=[1],递归进入下一层。
    • 第二层backtrackpath=[1],遍历i=1nums[1]=2未使用),标记used[1]=truepath=[1,2],递归进入下一层。
    • 第三层backtrackpath=[1,2],遍历i=2nums[2]=3未使用),标记used[2]=truepath=[1,2,3]。此时path.size() == 3,将[1,2,3]加入result,返回上一层。
    • 回溯操作:第三层返回后,执行path.remove(2)path变回[1,2]),used[2]=false;第二层继续遍历i=2nums[2]=3未使用),重复上述逻辑生成[1,3,2],再回溯到第一层,继续尝试i=1nums[1]=2),最终生成所有6种排列。

复杂度分析

  • 时间复杂度O(n * n!)
    总共有n!个排列(n为数组长度),每个排列需要O(n)时间构建(将path加入result时需复制n个元素)。
  • 空间复杂度O(n)
    递归栈深度最大为n(构建完整排列时),pathused数组的大小均为n,与n!无关。

边界测试用例验证

  1. 示例1:nums = [1,2,3]
    输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]](代码可生成所有6种排列)。
  2. 示例2:nums = [0,1]
    输出:[[0,1],[1,0]](正常生成2种排列)。
  3. 示例3:nums = [1]
    输出:[[1]](终止条件直接触发,加入唯一排列)。
http://www.dtcms.com/a/423651.html

相关文章:

  • C++版搜索与图论算法
  • 天津做网站排名企业网站建设的价格
  • Nginx 反向代理、负载均衡与 Keepalived 高可用
  • nginx upstream的作用
  • BeaverTails数据集:大模型安全对齐的关键资源与实战应用
  • 归并排序、计数排序以及各种排序稳定性总结
  • 【数据结构+算法】迭代深度搜索(IDS)及其时间复杂度和空间复杂度
  • OpenSpeedy下载 - 全平台网盘提速加速工具|官网入口
  • 关于在博客页面添加live2d-widget的一些心得和踩过的坑
  • 2025年,今后需要进步的方面
  • 有哪些做平面设计好素材网站自学it怎么入门
  • Android16 adb投屏工具Scrcpy介绍
  • 酵母展示技术如何重塑酶工程?从定向进化到工业催化的突破
  • 广汉做网站立白内部网站
  • 【FPGA+DSP系列】——(3)中断学习(以定时器中断为例)
  • 重庆网上注册公司网站配置 wordpress
  • ECMAScript 2025 有哪些新特性?
  • CSP-S 提高组 2025 初赛试题解析(第三部分:完善程序题(二)(39-43))
  • 前端实战:基于React Hooks与Ant Design V5的多级菜单系统
  • 单片机OTA升级:高效无线更新的秘密
  • 社区平安建设基层网站重庆企业网站建设官网
  • 嵌入式学习笔记4.STM32中断系统及外部中断EXTI
  • 手机网站模板大全上海市公共招聘网官网
  • Python爬虫实战:获取国家天文数据中心公开的观测信息与数据分析
  • 中核西北建设集团网站苏州手机社区网站建设
  • 网站建设皿金手指谷哥壹柒小米发布会2022
  • 实战:用Scrapy框架搭建第一个爬虫项目
  • Kubernetes 的本质:一个以 API 为中心的“元操作系统”
  • 网站设计的公司选哪家陕西建设网官网登录
  • 基于EasyExcel、FastExcel封装spring boot starter