LeetCode47-全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
一、思路
(一)回溯算法
无重复的全排列可以使用回溯算法,那么有重复的可不可以呢?
当然可以,只要使用集合去重即可!!!
C++代码:
class Solution {
public:
set<vector<int>> results;
vector<bool> pos;
vector<vector<int>> permuteUnique(vector<int>& nums) {
if (nums.empty())
return vector<vector<int>>(results.begin(), results.end());
vector<int> res;
vector<bool> p(nums.size(), true);
pos = p;
recall(nums, res);
return vector<vector<int>>(results.begin(), results.end());
}
void recall(vector<int>& nums, vector<int>& res) {
if (res.size() == nums.size()) {
results.insert(res);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (pos[i]) {
pos[i] = false;
res.push_back(nums[i]);
recall(nums, res);
pos[i] = true;
res.pop_back();
}
}
}
};
执行效率:
(二)改进方法(一)
观察一下重复的原因:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
可以发现,如果本轮进入向量的是元素A,而下一轮进入向量的还是元素A,则会导致重复!!!!
算法流程:
(1)排序
(2)检查当前元素是否标记过
- 已经标记过,直接进入下一轮(2)
- 未标记,继续(3)
(3)检查当前元素与前一元素是否相等
- 不相等,将该元素放入向量,进入下一轮(2)
- 相等,继续判断
(4)判断前一元素是否被标记过了
- 没有被标记,则说明在上一轮中,这个元素已经被使用过了,本轮结束,下一轮(2)
- 标记了,则表明这个重复元素在向量里面,不会因为:当前元素=前一元素,而造成排列重复,将当前元素放入向量,进入下一轮(2)
C++代码:
class Solution {
public:
vector<vector<int>> results;
vector<bool> pos;
vector<vector<int>> permuteUnique(vector<int>& nums) {
if (nums.empty())
return results;
sort(nums.begin(), nums.end());
vector<int> res;
vector<bool> p(nums.size(), true);
pos = p;
recall(nums, res);
return results;
}
void recall(vector<int>& nums, vector<int>& res) {
if (res.size() == nums.size()) {
results.push_back(res);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (!pos[i])
continue;
if (i > 0 && nums[i] == nums[i - 1] && !pos[i - 1])
continue;
pos[i] = false;
res.push_back(nums[i]);
recall(nums, res);
pos[i] = true;
res.pop_back();
}
}
};
执行效率: