前言
LeetCode题目:LeetCode 491、46、47
Takeaway:回溯模板+回溯的子集问题+回溯的排列问题+各种不同类型的去重(同枝,同层)
一、491
回溯子集问题,同层去重,但是去重方法不一样了,为了满足子集是递增的,不能进行排序,因为排序之后全是递增了,所以要用新的去重方法—unordered_set,其特点是回溯过程不需要删除,理由是每层都初始化一个新的set,彼此之间是独立的。
class Solution {
public:
vector<vector<int>> ans;
vector<int> each;
void traverse(vector<int>& nums, int startIndex) {
if(each.size()>=2){
ans.push_back(each);
}
unordered_set<int> used;
for(int i=startIndex; i<nums.size(); i++){
// 不是递增序列 或者 同层内出现重复
if ((!each.empty() && nums[i] < each.back()) || used.find(nums[i]) != used.end()) {
continue;
}
used.insert(nums[i]);
each.push_back(nums[i]);
traverse(nums, i+1);
each.pop_back();
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
traverse(nums, 0);
return ans;
}
};
二、46
回溯排列问题,特点是不需要使用start了,因为每次都是从开始选择;此外由于本题给的数组不包含重复元素,所以也不需要进行同层去重,只需要检查同一枝叶上该元素是否用过。
class Solution {
public:
vector<vector<int>> ans;
vector<int> each;
void traverse(vector<int>& nums, unordered_set<int> used){
if(each.size() == nums.size()){
ans.push_back(each);
return;
}
for(int i=0; i<nums.size(); i++){
if(each.size()>0 && used.find(nums[i])!=used.end()){
continue;
}
used.insert(nums[i]);
each.push_back(nums[i]);
traverse(nums, used);
used.erase(nums[i]);
each.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
//这个东西的位置,放递归里面查层重,放外面查枝叶重
unordered_set<int> used;
traverse(nums, used);
return ans;
}
};
三、47
回溯排列问题,在46题基础上,增加了给出元素可能重复的限制,这样就需要进行同层去重了。
class Solution {
public:
vector<vector<int>> ans;
vector<int> each;
void traverse(vector<int>& nums, vector<bool> used) {
if(each.size() == nums.size()){
ans.push_back(each);
return;
}
for(int i=0; i<nums.size(); i++){
// 当前元素同一树枝上没使用过,但是同层有人使用过相同的值的元素了,
// 如果使用的话就会出现两个[1,1,2],故跳过
if(i>0 && nums[i]==nums[i-1] && used[i-1] == false){
continue;
}
// 当前元素同一树枝上没使用过此元素,如果已经用过了自然不能重复使用
// (相同元素不是相同大小的元素!)
if(used[i] == false){
used[i] = true;
each.push_back(nums[i]);
traverse(nums, used);
used[i] = false;
each.pop_back();
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<bool> used(nums.size(), false);
// 排序好很重要,不然无法保证相同元素连在一起。
sort(nums.begin(), nums.end());
traverse(nums, used);
return ans;
}
};
总结
回溯模板+回溯的子集问题+回溯的排列问题+各种不同类型的去重(同枝,同层)。