问题:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
思路一:与无重复字符的解决方法类似,采用递归的方法,不断地递归交换元素的位置,但是要判断需要交换位置的两个元素值是否相同,如果相同,则交换下一位置。
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>>res = new ArrayList<>();
dfs(res,nums,0);
return res;
}
public void dfs(List<List<Integer>>res ,int nums[],int start){
if(start == nums.length){
List<Integer>temp = new ArrayList<>();//存储排列后序列
for(int s:nums) temp.add(s);
res.add(temp);
}
//递归交换元素位置
for(int i = start;i<nums.length;i++){
if(!isSwap(nums,start,i)){//判断是否交换
continue;
}
swap(nums,i,start);
dfs(res,nums,start+1);
swap(nums,i,start);
}
}
//交换函数
public void swap(int nums[],int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//判断是否交换
public boolean isSwap(int nums[],int i,int j){
for(int k = i;k<j;k++){
if(nums[k]==nums[j]){
return false;
}
}
return true;
}
}
思路二:采用非递归的方法,采用插入法,与前述的无重复字符类似,不过每次插入新值后存放在集合set中,这样重复的序列无法存放近set集合中
class Solution{
public List<List<Integer>>permuteUnique(int []nums){
Set<List<Integer>> res = new HashSet<>();//存放全排列后的序列
ArrayList<Integer> first = new ArrayList<>();
first.add(nums[0]);//存储首位置数字
res.add(first);//存放第一个列表对象
for(int i= 1;i<nums.length;i++){
Set<List<Integer>> newRes = new HashSet<>();//存放每次插入新值的列表对象
for(List<Integer> temp:res){//待插入序列
int size = temp.size()+1;
for(int j = 0;j<size;j++){
List<Integer>item = new ArrayList<>(temp);//暂存待插入序列
item.add(j,nums[i]);//插入新值
newRes.add(item);
}
}
res = newRes;
}
return new ArrayList<List<Integer>>(res);
}
}