回溯算法:排列问题(二)

47. 全排列 II

给定一个可包含重复数字的序列nums,按任意顺序返回所有不重复的全排列。

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

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

思路

这道题目和回溯算法:排列问题的区别在:给定一个可包含重复数字的序列,要返回所有不重复的全排列。

前面讲解了组合问题子集问题如何去重,其实排列问题也是一样的套路。

注意去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。

一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。

代码

class Solution {
    List<Integer> temp = new ArrayList<Integer>();
    List<List<Integer>> ans = new ArrayList<List<Integer>>();

    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums);
        backtracking(nums,used);
        return ans;
    }
    private void backtracking(int[] nums,boolean[] used) {
        if(temp.size() == nums.length) {
            ans.add(new ArrayList<>(temp));
            return;
        }

        // 遍历可能的搜索起点
        for (int i = 0; i < nums.length; i++) {
            // used[i - 1] == true,说明同一树支nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if(i>0 && nums[i]==nums[i-1] && used[i-1] == false){
                continue;
            }
            if(used[i] == false) {
                temp.add(nums[i]);
                used[i] = true;
                backtracking(nums,used);
                temp.remove(temp.size()-1);
                used[i]=false;
            }
        }
    }
}
posted @ 2021-05-23 18:09  当康  阅读(81)  评论(0编辑  收藏  举报