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;
}
}
}
}