From : https://leetcode.com/problems/permutations-ii/
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]
.
Solution :
思路:采用字典序的非递归方法。从字典顺序最小的一种排列开始,每次获得字典序刚好比前一个排列大的排列,直到得到字典序最大的排列时,就得到了所有的结果,以字符串"abc"为例,"abc"是字典序最小的排列,所有情况按字典序排列为"abc","acb","bac","bca","cba","cab"。
具体步骤为为:
1.字符串进行排序,得到字符串的最小字典序排列(C0C1C2...Cn),Ci<=Ci+1。
2.从后往前,找到一对相邻的升序元素CiCi+1,(Ci<Ci+1),如果遍历完字符串找不到这样的相邻升序对,说明已经达到了字典序最大的全排列
3.从字符串结束位置到位置i遍历,找到比Ci大的元素Cj,交换Cj的位置
4.将Ci+1到Cn所有的字符逆序,这样得到的排列刚好比之前的字典序大(因为转换后Ci+1<Ci+2<...<Cn,为最小字典序)。
5.重复3,4,5过程直到字典序最大。
class Solution {
public:
void swap(int &i,int &j) {
i ^= j;
j ^= i;
i ^= j;
}
vector<vector<int>> permuteUnique(vector<int> &num) {
vector<vector<int>> res;
int i, j, n=num.size();
sort(num.begin(),num.end());
res.push_back(num);
while(true) {
for(i=n-2; i>=0; i--)
if(num[i] < num[i+1])
break;
if(i<=-1) return res;
for(j=n-1; j>i; j--)
if(num[j] > num[i])
break;
swap(num[i],num[j]);
for(int k=i+1; k<(i+1+n)/2; k++)
swap(num[k], num[n-(k-i)]);
res.push_back(num);
}
return res;
}
};
精简优化一下结构:
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Arrays.sort(nums);
do {
ans.add(toList(nums));
} while(hasNextPermute(nums));
return ans;
}
private boolean hasNextPermute(int[] nums) {
int len = nums.length, j = len-2, k = len-1;
while(j>=0 && nums[j]>=nums[j+1]) --j;
if(j == -1) {
return false;
}
for(int n=nums[j]; n>=nums[k]; --k) {}
swap(nums, k, j);
swapAll(nums, j+1, len-1);
return true;
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
private void swapAll(int[] nums, int i, int j) {
while(i < j) {
swap(nums, i++, j--);
}
}
private List<Integer> toList(int[] nums) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0; i<nums.length; ++i) {
list.add(nums[i]);
}
return list;
}
}
先对数组进行排序,这样在DFS的时候,可以先判断前面的一个数是否和自己相等,相等的时候则前面的数必须使用了,自己才能使用,这样就不会产生重复的排列了。
class Solution {
public:
void dfs(int dep, vector<int> &num) {
if(dep == n) {
ans.push_back(cur);
return;
}
for(int i = 0; i < n; i++) {
if (canUse[i]) {
if (i != 0 && num[i] == num[i-1] && canUse[i-1]) continue;
canUse[i] = false;
cur[dep] = num[i];
dfs(dep + 1, num);
canUse[i] = true;
}
}
}
vector<vector<int>> permuteUnique(vector<int> &num) {
n = num.size();
sort(num.begin(), num.end());
cur = vector<int>(n);
canUse = vector<bool>(n, true);
ans.clear();
dfs(0, num);
return ans;
}
private:
int n;
vector<bool> canUse;
vector<int> cur;
vector<vector<int> > ans;
};
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
boolean[] used = new boolean[nums.length];
dfs(nums, 0, used, new int[nums.length], ans);
return ans;
}
private void dfs(int[] nums, int index, boolean[] used, int[] cur, List<List<Integer>> ans) {
if(index == nums.length) {
ans.add(toList(cur));
return;
}
for(int i=0; i<nums.length; ++i) {
if(used[i] || i > 0 && nums[i]==nums[i-1] && !used[i-1]) continue;
used[i] = true;
cur[index] = nums[i];
dfs(nums, index+1, used, cur, ans);
used[i] = false;
}
}
private List<Integer> toList(int[] nums) {
List<Integer> l = new ArrayList<Integer>();
for(int i : nums) {
l.add(i);
}
return l;
}
}