• 全排列[中等]


    优质博文:IT-BLOG-CN

    一、题目

    给定一个不含重复数字的数组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]和[2,1]是不同的,但在组合中[1,2]和[2,1]是相同的。

    我们已简单的[1,2,3]为一组,看下排列的搜索树:

    解题思路:
    【1】使用数组path记录路径上的数(已选数字)
    【2】集合s记录剩余未选的数

    回溯三问:
    【1】当前操作?从s中枚举path[i]要填入的数字x
    【2】子问题?构造排列 >= i 的部分,剩余未选数字集合为s
    【3】下一个子问题?构造排列 >= i + 1 部分,剩余未选数字结合为s-{x}

    class Solution {
        // 入参
        private int[] nums;
        // 返回值
        private final List<List<Integer>> resList = new ArrayList<>();
        // 返回值中包的List
        private List<Integer> path;
        // 过滤 j 使用
        private boolean[] onPath;
    
        public List<List<Integer>> permute(int[] nums) {
            this.nums = nums;
            path = Arrays.asList(new Integer[nums.length]);
            onPath = new boolean[nums.length];
            dfs(0);
            return resList;
        }
    
        // 回溯方法
        private void dfs(int i) {
            // 回溯方法的退出条件
            if (i == nums.length) {
                // 这里需要copy path, 不能直接赋值,因为path一直变化
                resList.add(new ArrayList(path));
                System.out.println("resList : " + resList.toString());
                return;
            }
    
            // 每个i进来,组装一次结果
            for (int j = 0; j < nums.length; j++) {
                // 过滤j,原因在循环中有说明
                if (!onPath[j]) {
                    // 当 i 递增时,j也在递增
                    path.set(i, nums[j]);
                    System.out.println(path.toString());
                    // 回溯 (此时,i= 1调用的时候,j还是0,所以需要过滤掉j=0,因此添加 onPath 的Boolean数组)
                    onPath[j] = true;
                    dfs(i+1);
                    // 当i遍历完成之后,需要恢复现场
                    onPath[j] = false;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    看下输出的流程:

    [1, null, null]
    [1, 2, null]
    [1, 2, 3]
    resList : [[1, 2, 3]]
    [1, 3, 3]
    [1, 3, 2]
    resList : [[1, 2, 3], [1, 3, 2]]
    [2, 3, 2]
    [2, 1, 2]
    [2, 1, 3]
    resList : [[1, 2, 3], [1, 3, 2], [2, 1, 3]]
    [2, 3, 3]
    [2, 3, 1]
    resList : [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]]
    [3, 3, 1]
    [3, 1, 1]
    [3, 1, 2]
    resList : [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]]
    [3, 2, 2]
    [3, 2, 1]
    resList : [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    附视频讲解

    时间复杂度: O(n⋅n!),其中nnums的长度。搜索树中的节点个数低于3⋅n!。实际上,精确值为⌊e⋅n!⌋,其中e=2.718⋯为自然常数。每个非叶节点要花费O(n)的时间遍历onPath数组,每个叶结点也要花费O(n)的时间复制path数组,因此时间复杂度为O(n⋅n!)
    空间复杂度: O(n)返回值的空间不计入。

  • 相关阅读:
    东方梅酒:梅见的新国饮故事
    大数据之Hadoop_Yarn的基本介绍,及入门程序的书写
    pythonn笔记 -- 模块、文件
    HarmonyOS开发案例:【图片编辑】
    整型在内存中的存储与管理
    PHP做app扫码登录的一些步骤和代码片段记录一下
    SAS学习8、9(方差分析、anova过程、相关分析和回归分析、corr过程、reg过程、多元线性回归、stepwise)
    ElasticSearch深度分页详解
    第五章(1):词嵌入进阶之Glove模型讲解与pytorch实现
    Word控件Spire.Doc 【段落处理】教程(四):如何在 C#、VB.NET 中设置 Word 项目符号样式
  • 原文地址:https://blog.csdn.net/zhengzhaoyang122/article/details/133589186