题目原型:
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]
, and [2,1,1]
.
基本思路:
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。用编程的话描述就是第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。
本算法中的sort(),swap()方法见 全排列的java实现(无重复元素)
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();//全局变量
//递归实现,有重复数字如:122
public ArrayList<ArrayList<Integer>> permuteUnique(int[] num)
{
//排序
sort(num, 0, num.length-1);
allRangeUnique(num, 0, num.length-1);
return result;
}
//能不能交换,就是说交换数字中间不能出现与后面交换的重复数字如:122那个1只能和第一个2交换却不能和第二个2交换
public boolean isSwap(int[] num , int i ,int j)
{
for(int index = i;index<j;index++)
{
if(num[index]==num[j])
return false;
}
return true;
}
public void allRangeUnique(int[] num,int cur,int sum)
{
if(cur==sum)
{
//添加result
add(result, num);
return;
}
else
{
for(int i = cur;i<=sum;i++)//第i个数分别与它后面的数字交换就能得到新的排列
{
//如果可以交换
if(isSwap(num, cur, i))//注意cur和i的顺序,cur在前,i在后
{
swap(num, i, cur);
allRangeUnique(num, cur+1, sum);//表示,若sur和sum相邻时输出
swap(num, i, cur);
}
}
}
}