这道题也是全排列问题,但是增加了题目的难度。因为这个给定的序列里面有重复元素,我开始的想法是设置一个map,然后每一个元素值是key,出现的数量是count,实际上这样做和设置visit数组是一样的做法,但是对于处理重复元素的问题,会出现更多的重复出现。因为这样做并没有记录那个元素被访问了。所以还是改为visit数组方法,但是我们会发现结果中会存在着大量的重复,比如(1,1,2),我们得到的结果可能是(1,1,2),(1,2,1)(1,1,2)。。。
因为全排列,所以每个位置上都有可能出现序列中的任意一个值,但是如果重复的话,visit数组是处理不了这种情况的,我们需要再剪枝,这时候我们想,如果我们是一个排序的数组,当第一个重复数字在某一个位置上,那么只会的重复数字是不是都不应该在这个位置上次出现,例如上面的那个列子。如果某一个位置上出现了第一个1,那么在后续的递归中我们是不是应该防止第二个位置在这个位置上出现,(这样做是因为我们每一次递归都是重零开始)。所以我们的第二个剪枝条件就出现了。
先判断是否相等,然后判断前一个位置是不是没又被访问,以为按照顺利来放置数字的话,第一个数字没有被放置,说明这个数字在这个位置上已经放置过了,然后被回溯了。现在我们就不应该在这个位置放置和他相同的数字。就有了下面的剪枝条件。
if(i>0&&nums[i]==nums[i-1]&&visited[i-1]==0)continue;
完成代码入下:
这个解法要求先对序列排序。
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>>res;
vector<int>visited(nums.size(),0);
dfs(res,nums,{},visited,0);
return res;
}
void dfs(vector<vector<int>>&res,vector<int>&nums,vector<int>out,vector<int>&visited,int level){
if(level==nums.size()){
res.push_back(out);
return;
}
for(int i=0;i<nums.size();i++){
if(i>0&&nums[i]==nums[i-1]&&visited[i-1]==0)continue;
if(visited[i]==0){
out.push_back(nums[i]);
visited[i]=1;
dfs(res,nums,out,visited,level+1);
out.pop_back();
visited[i]=0;
}
}
}