LeetCode 46. 全排列(回溯法)

一、核心思路

  1. 题目给定不含重复数字的数组,需要找出全部排列组合,适合回溯 DFS。

  2. 使用path记录当前正在构造的一条排列;used布尔数组标记下标对应的数字是否已经被选入 path,避免重复选取。

  3. 步骤:

    1. 终止条件:当前path的长度等于原数组长度,代表找到一组完整排列,复制存入结果集。
    2. 遍历每一个数字:如果该数字已经被使用,则跳过。
    3. 做选择:标记数字已使用,将数字加入 path。
    4. 递归:进入下一层,继续挑选剩下的数字。
    5. 回溯(撤销选择):递归返回后,移除 path 末尾数字,取消 used 标记,尝试其他分支。

二、完整 Java 代码

ini 复制代码
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        boolean[] used = new boolean[nums.length];
        backtrack(nums, used, path, res);
        return res;
    }

    private void backtrack(int[] nums, boolean[] used, List<Integer> path, List<List<Integer>> res){
        if(path.size() == nums.length){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(used[i]) continue;

            used[i] = true;
            path.add(nums[i]);

            backtrack(nums, used, path, res);

            path.remove(path.size()-1);
            used[i] = false;
        }
    }
}

三、实例演示(nums = 1,2,3)

步骤 path(当前排列) used 数组 操作说明
1 \[\] F,F,F i=0,未使用;used 0=true,path=1,递归
2 1 T,F,F i=0 跳过;i=1 未使用;used 1=true,path=1,2,递归
3 1,2 T,T,F i=0、1 跳过;i=2 未使用;used 2=true,path=1,2,3
4 1,2,3 T,T,T path 长度等于 3,存入 res;return 回溯
5 1,2 T,T,F 撤销:删掉 3,used 2=false;for 循环结束,回溯
6 1 T,F,F 撤销:删掉 2,used 1=false;i=2 未使用,path=1,3,递归
7 1,3 T,F,T i=1 未使用,path=1,3,2,存入 res,回溯
8 ...... ...... 持续回溯,依次探索 2,1,3、2,3,1、3,1,2、3,2,1

四、复杂度分析

  • 时间复杂度:(O(n * n!)),总共有 (n!) 种排列,每种排列复制数组花费(O(n))
  • 空间复杂度:(O(n)),递归栈、path 集合、used 标记数组,不计返回结果占用空间

五、易错点总结

  1. 保存结果必须写 res.add(new ArrayList<>(path)),不能直接 add (path),path 是同一个引用,后续回溯会修改内容。
  2. 回溯顺序固定:先递归,递归返回之后,再撤销选择(删元素、改 used) 。
  3. used 数组是按下标标记,不是按数值标记,适合本题无重复数字场景。

六、感悟

回溯本质就是暴力搜索所有可行方案,核心是「做选择 → 递归深入 → 撤销选择」,撤销选择就是回溯,保证不同搜索分支之间互不干扰。

相关推荐
文丑颜不良啊3 小时前
LeetCode476~500题目解析
java·leetcode
Tsuki_tl4 小时前
【优选算法:双指针】——复写零题解
java·c++·算法·leetcode·数组·双指针·复写零
Cccp.1236 小时前
【leetcode】(十四)从暴力递归到动态规划
数据结构·算法·leetcode·动态规划
旖旎夜光6 小时前
LeetCode 215: 数组中的第K个最大元素 (快速排序) —— 题解
c++·学习·算法·leetcode·力控
德彪稳坐倒骑驴7 小时前
Leetcode力扣刷题记录与题解
算法·leetcode·职场和发展
java_nnnn21 小时前
LeetCode刷题滑动窗口(水果成篮+找到字符串中所有字母的异位词)Java
java·开发语言·leetcode
文丑颜不良啊1 天前
LeetCode276~300题目解析
java·leetcode
傅科摆 _ py1 天前
链表力扣复习
数据结构·leetcode·链表
圣保罗的大教堂1 天前
leetcode 3863. 将一个字符串排序的最小操作次数 中等
leetcode