1. 题目
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]
]
2. 思路
和有重复的排列的区别是对重复元素要特殊处理。即重复元素在插入时其实保持有序即可。把重复元素当做a1 a2 a3的a。
具体做法是,在插入时如果当前插入元素a是在递归子集中已经存在的元素,则新插入的位置是在已有序列的最后一个a之后的位置开始。
比如112, 12的已有集合是{12,21}, 下一个1插入时,再插入{12}时只能在2之前开始插入,得到{112,121}。{21}在插入时只能在1之后开始插入,得到{211}。
3. 代码
耗时:43ms
class Solution {
public:
// 和非重复的类似, 但是将beg元素向已递归结果里插入时,先找到等于自己的节点的位置,从其之后然后开始插入
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end()); // 排序是为了方便判断当前字符是否是重复数字
return permute(nums, 0);
}
vector<vector<int>> permute(vector<int>& nums, int beg) {
int sz = nums.size();
vector<vector<int>> ret;
if (sz == beg) { return ret; }
if (sz == beg + 1) {
vector<int> one;
one.push_back(nums[beg]);
ret.push_back(one);
return ret;
}
vector<vector<int>> subs = permute(nums, beg+1);
// 将nums[beg]插入到subs的所有结果的所有位置,除了前一个元素等于自己的情况
int beg_v = nums[beg];
bool dup = sz >=2 && nums[beg+1] == nums[beg];
for (int i = 0; i < subs.size(); i++) {
vector<int>& vec_i = subs[i];
int j = 0;
if (dup) {
j = vec_i.size() - 1;
for (; j >= 0; j--) {
if (vec_i[j] == beg_v) {
j++;
break;
}
}
}
for (; j <= vec_i.size(); j++) { // j表示插入的位置
vector<int> cat;
for (int k = 0; k <= vec_i.size(); k++) {
if (k == j) {
cat.push_back(beg_v);
} else if (k < j) {
cat.push_back(vec_i[k]);
} else {
cat.push_back(vec_i[k-1]);
}
}
ret.push_back(cat);
}
}
return ret;
}
};