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);//删除元素
}
}
}
}