Fork me on GitHub

【LeetCode】47.全排列②

题目描述

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入:

[1,1,2]

输出:

[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

思路

这道题是上一道题的延伸,由于数组中有可能会出现重复的数字,按照之前的算法会有重复排列产生,因此我们需要判断前面一个数和当前的数是否相等,如果相等,且其对应的visited的值为1,当前数字才能使用,否则需要跳过,这样就不会产生重复排列了。下面方式一就是在排列一的基础上进行剪枝判断。
方式二则使用了set的天然去重功能实现的,总的来说方式二简单一些。

实现代码

方式一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> ret;
vector<int> out;
vector<int> visited(nums.size(),0);
sort(nums.begin(),nums.end());
premuteDFS(nums,0,visited,out,ret);
return ret;
}

void premuteDFS(vector<int> &num,int level, vector<int> &visited,vector<int> &out,vector<vector<int>>& ret){
if(level >= num.size()){
ret.push_back(out);
return ;
}
for(int i= 0;i<num.size();++i){
if(visited[i] == 1){
continue;
}
if(i>0&& num[i] == num[i-1] && visited[i-1]==0)
continue;
visited[i] = 1;
out.push_back(num[i]);
premuteDFS(num,level+1,visited,out,ret);
out.pop_back();
visited[i] = 0;

}

}
};

方式二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
set<vector<int>> res;
permute(nums,0,res);
return vector<vector<int>> (res.begin(),res.end());
}

void permute(vector<int> &nums,int start,set<vector<int>> &res){
if(start>= nums.size())
res.insert(nums);
for(int i=start;i<nums.size();++i){
if(i != start && nums[i]== nums[start])
continue;
swap(nums[i],nums[start]);
permute(nums,start+1,res);
swap(nums[i],nums[start]);
}
}
};

对于上面的方式二你可能还是疑惑的,我们明明剪枝了为什么还要set的去重?是不是有点重复对于了,其实不然,我们还原用vector数组,并且在主函数调用递归之前给nums排个序,然后测试【1,2,2】,得到结果:

[[1,2,2],[2,1,2],[2,2,1],[2,2,1],2,1,2]]

你会发现结果还是有重复的,那么上面的剪枝到底有啥用?做了啥?
其实,那个剪枝只是为了防止当start=1,i=2时,将两个2交换,这样可以防止(1,2,2)被放入两次。

本文标题:【LeetCode】47.全排列②

文章作者:LiuXiaoKun

发布时间:2019年05月04日 - 22:05

最后更新:2019年05月04日 - 22:05

原始链接:https://LiuZiQiao.github.io/2019/05/04/【LeetCode】47-全排列②/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%