问题
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
例子
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
分析
Permutations II和Permutations的不同点在于Permutations II的元素可以包含重复元素,而Permutations的元素是互不相同的。
同样可以使用Next Permutation法不断枚举出新的排列,因为Next Permutation能够解决重复元素问题;对于backtracing,我们首先要把元素排序,然后在不断交换元素的过程中,跳过重复元素,即不交换相同的元素。
要点
Next Permutation/backtracing
时间复杂度
- next permutation: O(n!*n)
- backtracing: O(n!)
空间复杂度
- next permutation: O(1)
- backtracing: O(n!)
代码
1.next permutation
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
res.push_back(nums);
if (nums.size() < 2) return res;
while (nextPermutation(nums))
res.push_back(nums);
return res;
}
private:
bool nextPermutation(vector<int>& nums) {
int p, q;
for (p = nums.size() - 2; p >= 0; p--)
if (nums[p] < nums[p + 1]) break;
if (p == -1) return false;
for (q = nums.size() - 1; q > p; q--)
if (nums[q] > nums[p]) break;
swap(nums[p], nums[q]);
reverse(nums.begin() + p + 1, nums.end());
return true;
}
};
2.backtracing
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> permutations;
sort(nums.begin(), nums.end());
permute(nums, 0, permutations);
return permutations;
}
private:
// 注意,是值传递,不是引用传递,所有不需要还原状态
// 使用引用传递不能保持集合元素的有序性,因此会生成很多重复的排列
void permute(vector<int> nums, int begin, vector<vector<int>> &permutations) {
if (begin == nums.size() - 1) {
permutations.push_back(nums);
return;
}
for (int i = begin; i < nums.size(); i++) {
if (i != begin && nums[i] == nums[begin]) continue;
swap(nums[i], nums[begin]);
permute(nums, begin + 1, permutations);
}
}
};