LeetCode 47. 全排列 II

201 阅读1分钟

47. 全排列 II

难度 中等

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

题解

这道题是个全排列的题目,但是不能出现重复的排列,因为在数组中有重复的元素,在全排列的时候,会出现重复的排列。那怎么去掉重复的排列是解题的关键。

例如给出的数据[1,2,2],第二第三个元素重复了,当我们枚举了一、二元素(即[1,2]),然后枚举一、三元素时(即[1,2]),这就有相同排列了。

再举个例子[1,2,2,2],当我们枚举了一、二、三元素(即[1,2,2]),然后枚举一、三、四元素时(即[1,2,2]),又出现相同排列了。

通过上面两个例子知道,当我们前面出现一个相同的元素(例如2),我们没有选择这个元素,此时选择当前位置的元素(2),就会出现重复的子集。因为如果选择了前一个元素;和另一种不选择前一个元素,选择当前元素;都是同样的排列。所以我们要处理这种情况,判断前一个元素是否选取,然后和前一个元素是否相同。(选不选取用visit数组)

if(i > 0 && !visit[i - 1] && nums[i - 1] == nums[i]){//前面一个元素没有选取,当前元素和前一个元素相同,跳过循环
    continue;
}

AC代码:

class Solution {
    List<List<Integer>> ans = new ArrayList<List<Integer>>();//结果集
    List<Integer> queue = new ArrayList<Integer>();//辅助队列
​
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);//排序
        boolean[] visit = new boolean[nums.length];//访问数组
        dfs(0, nums, visit);
        return ans;
    }
​
    void dfs(int k, int[] nums, boolean[] visit){
        if(k == nums.length){//枚举长度等于数组长度,得到排列结果
            ans.add(new ArrayList<Integer>(queue));
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(!visit[i]){//当前元素没有访问
                if(i > 0 && !visit[i - 1] && nums[i - 1] == nums[i]){//前面一个元素没有选取,当前元素和前一个元素相同,跳过循环
                    continue;
                }
                queue.add(nums[i]);//添加元素
                visit[i] = true;//标志为访问位
                dfs(k + 1, nums, visit);
                visit[i] = false;//恢复访问位
                queue.remove(queue.size() - 1);//删除元素
            }
        }
    }
}