给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
int[] nums;
List<Integer> temp=new ArrayList<>();
List<List<Integer>> ans=new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
this.nums=nums;//这里要加上this
for(int t:nums) temp.add(t);
backtrack(0);
return ans;
}
public void backtrack(int index){
if(index>=nums.length){
ans.add(new ArrayList<>(temp));
return ;
}
for(int i=index;i<nums.length;i++){
if(swaped(index,i)==true){
Collections.swap(temp,i,index);
//swap的含义就是把nums[i],分别依次换到index位置上
backtrack(index+1);
Collections.swap(temp,i,index);
}
}
}
public boolean swaped(int start,int end){
//从star到end之间的nums[i],如果end和nums[i]相同,就不用把nums[end]换到start位置上,因为nums[start]和nums[i]换过了
for(int i=start;i<end;i++){
if(temp.get(i)==temp.get(end)) //cur位置换过了相同的数字,就不能再换相同数字了
return false;
}
return true;
}
}
HashSet去重代码:效率比较低,但是挺万能的
class Solution {
HashSet<List<Integer>> set=new HashSet<>();
int[] nums;
List<Integer> temp=new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
this.nums=nums;//这里要加上this
for(int t:nums) temp.add(t);
backtrack(0);
List<List<Integer>> ans=new ArrayList<>();
for(List<Integer> t:set) ans.add(t);
return ans;
}
public void backtrack(int index){
if(index>=nums.length){
set.add(new ArrayList<>(temp));
return ;
}
for(int i=index;i<nums.length;i++){
Collections.swap(temp,i,index);
backtrack(index+1);
Collections.swap(temp,i,index);
}
}
}
下面代码看看就好
这里的去重操作很巧妙if (i > 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0)
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>(); // 记录最终答案
if (nums == null || nums.length == 0) return res;
// visited[i] == 0时,未访问;== 1时,已访问
int[] visited = new int[nums.length];
Arrays.sort(nums); // 排序后容易去重
backTrack(res, nums, new ArrayList<Integer>(), visited);
return res;
}
private void backTrack(List<List<Integer>> res, int[] nums, List<Integer> list, int[] visited) {
// 列表长度为数组长度时,拷贝列表到结果列表中
if (list.size() == nums.length) {
res.add(new ArrayList<>(list));
return ;
}
for (int i = 0; i < nums.length; i++) {
if (visited[i] == 1) continue; // 已访问过,跳过这层循环
// 如果数组相连元素相等,没有先访问前面的元素,就不会存在重复
//说明前面的元素已经访问过了
if (i > 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0){
continue;
}
// 加入列表中,标记为已访问,回溯求值
list.add(nums[i]);
visited[i] = 1;
backTrack(res, nums, list, visited);
// 回溯后,重新标记为未访问,删掉最后一个元素
visited[i] = 0;
list.remove(list.size() - 1);
}
}
}