【回溯】LCR 084. 全排列 II

LCR 084. 全排列 II

解题思路

  • 排序数组: 通过 Arrays.sort(nums) 将输入数组 nums 进行排序,这有助于确保相同的元素在一起,从而方便后续剪枝操作。

  • 初始化变量: 创建一个存储全排列结果的二维列表 res,一个用于暂存当前排列的列表 track,以及一个布尔数组 used 用于记录元素的使用情况。

  • 主函数: permuteUnique 是主函数,调用时传入待排列的数组 nums。在函数内部,首先对数组进行排序,然后初始化 used 数组,并调用 backtrack 函数开始回溯。

  • 回溯函数: backtrack 是递归的回溯函数,负责生成全排列。

    • 叶子节点处理: 当 track 的长度等于数组长度时,即找到一个全排列,将其添加到结果列表 res 中。

    • 元素选择: 使用 for 循环遍历数组中的元素,根据一定条件进行选择或剪枝。

    • 排除已选择的元素: 如果 used[i] 为 true,说明该元素已经被选择,直接跳过。

    • 剪枝操作: 利用排序后的数组,当当前元素与前一个元素相同,并且前一个元素未被使用时,跳过当前元素,以避免生成重复排列。

    • 选择当前元素: 将当前元素加入 track 列表,标记为已使用,然后递归调用 backtrack。

    • 撤销选择: 在递归完成后,撤销选择,即将 track 列表的最后一个元素移除,同时标记当前元素为未使用。

class Solution {

    List<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> track = new LinkedList<>();
    boolean[] used;

    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);// 先排序 让相同元素在一起
        used = new boolean[nums.length];
        backtrack(nums);
        return res;
    }

    void backtrack(int[] nums){
        // 收集叶子节点
        if(track.size() == nums.length){
            // 全排列 树的高度是数组长度
            res.add(new LinkedList<>(track));
            return;
        }

        for(int i = 0; i < nums.length; i++){
            // 排除已经选过的
            if(used[i] == true){
                continue;
            }

            // 也就是元素虽然相同  但是没被使用过
            if(i > 0 && nums[i] == nums[i - 1] && !used[i - 1]){
                continue;
            }

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

            backtrack(nums);

            // 撤销选择
            track.removeLast();
            used[i] = false;
        }
    }
}

你可能感兴趣的:(#,Leetcode,算法,排序算法,数据结构)