题目
给出一组可能包含重复项的数字,返回该组数字的所有排列。结果以字典序升序排列。
数据范围: 0 < <n≤8 ,数组中的值满足 -1≤val≤5
要求:空间复杂度 O(n!),时间复杂度 O(n!)
思路
1. 方法一:基于交换,使用set去重
set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。
做法与 无重复项的重排列 一样,只不过存储结果的res类型由二维数组改成set类型
2. 方法二 基于辅助数组
这道题类似没有重复项数字的全排列,但是因为交换位置可能会出现相同数字交换的情况,出现的结果需要去重,因此不便于使用交换位置的方法。
我们就使用临时数组去组装一个排列的情况:每当我们选取一个数组元素以后,就确定了其位置,相当于对数组中剩下的元素进行全排列添加在该元素后面,给剩余部分进行全排列就是一个子问题,因此可以使用递归。
代码
1. 方法一:使用set数据结构
class Solution {
public:
void recruit(set<vector<int>> &res, vector<int> &num, int index){
if(index == num.size()-1)
res.insert(num);
else{
for(int i = index; i < num.size(); i++){
if(i != index && num[i] == num[index])
continue;
swap(num[i], num[index]);
recruit(res, num, index+1);
swap(num[i], num[index]);
}
}
}
vector<vector<int> > permuteUnique(vector<int> &num) {
sort(num.begin(), num.end());
set<vector<int>> res;
recruit(res, num, 0);
vector<vector<int>> ret;
for(auto it : res){
ret.push_back(it);
}
return ret;
}
};
方法二
class Solution {
public:
void dfs(vector<vector<int>>& res, vector<int>& num, vector<bool>& vis,
vector<int>cur) {
if (cur.size() == num.size()) {
res.push_back(cur);
return;
}
for (int i = 0; i < num.size(); i++) {
if (vis[i])每次递归从头遍历数组,获取数字加入:首先根据vis数组,已经加入的元素不能再次加入了;
continue;
if (i > 0 && num[i - 1] == num[i] && !vis[i - 1])//同时,如果当前的元素num[i]与同一层的前一个元素num[i-1]相同且num[i-1]已经用,也不需要将其纳入。
continue;
vis[i] = true;
cur.push_back(num[i]);
dfs(res, num, vis, cur);
cur.pop_back();
vis[i] = false;
}
}
vector<vector<int> > permuteUnique(vector<int>& num) {
sort(num.begin(), num.end());
vector<vector<int>> res;
vector<bool> vis(num.size(), false);
vector<int> cur;
dfs(res, num, vis, cur);
return res;
}
};