【leetcode】47.(Medium)PermutationsII
阿新 • • 發佈:2018-11-10
解題思路:
參考
首先進行排序;
如果陣列中沒有重複的數字,就按照permutations的方法來做就可以了;
如果陣列中有2個重複的數字,比如[1,1,3],首先將陣列分為[1]和[1,3],
對[1,3]進行全排列有[1,3]和[3,1],在所有子全排列中的對應重複數字的後面新增數字即可,
比如我還需要新增1,第一個子全排列[1,3]的對應重複數字為1,1在第0位,所以我們在第1、2位分別再新新增進1,可以得到[1,1,3]和[1,3,1],
第二個子全排列[3,1]的對應重複數字1在第1位,所以我們只能在第二位新增進新的1,得到[3,1,1];
由此得到所有的全排列組合[1,1,3] [1,3,1]和[3,1,1];
如果有三個重複的數字,比如[1,1,1,3],首先將陣列分為[1]和[1,1,3],通過遞迴可以得到[1,1,3]的全排列[1,1,3] [1,3,1] [3,1,1],
第一個全排列[1,1,3]的最後一個重複數字1在第1位(從0開始計),然後我們就在第2、3位新增新的1,得到[1,1,1,3]和[1,1,3,1]
第二個全排列[1,3,1]的最後一個重複數字1在最後一位,所以我們只能在最後一位的後面新增進新的1,得到[1,3,1,1]
對[3,1,1]進行相同的處理,可以得到[3,1,1,1]
這樣就可以得到最終的所有結果了[1,1,1,3]、[1,1,3,1]、[1,3,1,1] 、 [3,1,1,1]
提交程式碼:
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
//DP
List<List<Integer>> lists=new ArrayList<List<Integer>>();
if(nums==null||nums.length==0) return lists;
if(nums.length==1) {
List<Integer> list= new ArrayList<Integer>();
list.add(nums[0]);
lists.add(list);
return lists;
}
//merge sort
mergeSort(nums,0,nums.length-1);
//build subnums and calculate sublists
int subnums[]=new int[nums.length-1];
for(int i=1,j=0;i<nums.length;i++,j++)
subnums[j]=nums[i];
List<List<Integer>> sublists=permuteUnique(subnums);
//create current lists
for(int i=0;i<sublists.size();i++) { //子排列的個數
if(nums[0]==nums[1]) {
int startpos=0,flag=nums[1];
for(int pos=sublists.get(i).size()-1;pos>=0;pos--)
if(sublists.get(i).get(pos)==flag){
startpos=pos+1;
break;}
while(startpos<nums.length) {
List<Integer> list=new ArrayList<Integer>();
for(int j=0;j<sublists.get(i).size();j++)
//list=sublists.get(i); //不能直接get,不然對list的改動也會變更到sublists中去
list.add(sublists.get(i).get(j));
list.add(startpos, nums[0]);
lists.add(list);
startpos++;
}
}
else {
for(int pos=0;pos<nums.length;pos++) {
List<Integer> list=new ArrayList<Integer>();
//copy the i'th sublist to list
for(int j=0;j<sublists.get(i).size();j++)
list.add(sublists.get(i).get(j));
//list=sublists.get(i);
list.add(pos,nums[0]);
lists.add(list);
}
}
}
return lists;
}
public void mergeSort(int nums[],int left,int right) {
if(left>=right) return;
int mid=(left+right)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
public void merge(int nums[],int left,int mid,int right) {
if(left==right) return;
int len=right-left+1;
int[] tmp=new int[len];
int i=left,j=mid+1,k=0;
while(i<=mid&&j<=right)
tmp[k++]=nums[i]<nums[j]?nums[i++]:nums[j++];
while(i<=mid)
tmp[k++]=nums[i++];
while(j<=right)
tmp[k++]=nums[j++];
for(k=0;k<len;k++)
nums[left++]=tmp[k];
}
}
執行結果: