题目描述:
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
方法1:递归回溯
主要思路:更详细题解参考官方题解
(1)这里和46 全排列使用的思路不太一样,在 46 全排列中由于不存在重复的元素,故直接在原始的数组中进行交换操作,本题中存在重复的元素,故将原数组排序后,只是作为遍历的对象,中间结果另存为一个数组中;
(2)这样的话,就需要一个标志数组来标识当前数组是否被访问过vector sign(nums.size(),false);
(3)同时,为了去除重复的元素,需要增加去除可能的重复的结果的判断,既 if(i>0&&nums[i]==nums[i-1]&&!sign[i-1]);
(4)其他的操作是正常的递归回溯方式;
void helper(vector<int>&nums,int depth,vector<int>& tmp,vector<bool>&sign, vector<vector<int>>& res){
//终止条件,既深度满足要求
if(!depth){
res.push_back(tmp);
return;
}
//遍历数组
for(int i=0;i<nums.size();++i){
//不能再次访问已经访问过的元素
if(sign[i])
continue;
//去重操作,既当前选择和前一个选择相同,当前一个选择显示没有访问,
//说明同一层的之前选择已经访问过了,现在是同一层的后面相同的选择,故直接跳过
if(i>0&&nums[i]==nums[i-1]&&!sign[i-1])
continue;
tmp.push_back(nums[i]);//压入可行的选择
sign[i]=true;//将对应的选择标识
helper(nums,depth-1,tmp,sign,res);//继续递归回溯
tmp.pop_back();//恢复选择之前的状态,以是同层的后续的选择可以进行
sign[i]=false;//将对应的选择的标识恢复
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
//处理特殊的情形
if(nums.empty())
return vector<vector<int>>();
//排序原数组
sort(nums.begin(),nums.end());
vector<vector<int>> res;
vector<int> tmp;
vector<bool> sign(nums.size(),false);//标识数组元素的访问情形
helper(nums,nums.size(),tmp,sign,res);//递归回溯
return res;
}
};