题目链接:https://leetcode-cn.com/problems/permutations-ii/
题目描述
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
思路
这题与 题46 全排列 类似,都是用回溯的思路解决,主要区别在于需要去重。
1 回溯
(1)首先需要对数组进行排序
(2)去重通过判断进行
if(i!=begin && nums[i] == nums[begin]) continue; // 如果后续有重复数字 不需要交换
- 注意传入的
nums
是拷贝不是引用!引用会导致nums
改变,而使得判断条件失效导致重复 - 并且
swap(nums[i],nums[begin]);
只需要执行一次,不需要再恢复现场。恢复现场反而会导致判断条件失效引起重复。
以[1,1,2,2] 为例,如果交换完位置1和2的元素后,为[1,2,1,2],如果恢复现场,则nums又变为[1,1,2,2] 此时交换位置1和3的元素(begin = 1,i=3, nums[begin] =1 != 2 = nums[i] 去重条件失效),又为[1,2,1,2],造成重复。
所以该解法中 拷贝复制+去重条件+不用恢复现场是环环相扣的,缺一不可。
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> ret;
if(nums.empty()) return ret;
sort(nums.begin(), nums.end());
permuteUniqueCore(nums,0,ret);
return ret;
}
private:
void permuteUniqueCore(vector<int> nums, int begin, vector<vector<int>>& ret){ // 注意传入的nums不是引用!!是拷贝
if(begin>= nums.size()){ // 到达最后元素,打印
ret.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]);
permuteUniqueCore(nums, begin+1, ret); // begin+1递归
}
}
};