目录
78.子集
方法一、迭代法实现子集枚举
方法二、递归法实现子集枚举
方法三、根据子集元素个数分情况收集
方法四、直接回溯法
90.子集二
方法一、迭代法实现子集枚举
方法二、递归法实现子集枚举
方法三、根据子集元素个数分情况收集
方法四、直接回溯法
78.子集
78. Subsets
方法一、迭代法实现子集枚举
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> aset;
int n = nums.size();
int m = 1<<n;//pow(2,n);//子集总数是2的n次方个
for(int mask = 0;mask <m;mask++){
aset.clear();
for(int i = 0;i < n;i++){
if(mask & (1<<i))
aset.push_back(nums[i]);
}
res.push_back(aset);
}
return res;
}
};
方法二、递归法实现子集枚举
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums,int index){
if(index == nums.size()){
res.push_back(aset);
return;
}
//当前子集选择nums[index]
aset.push_back(nums[index]);
dfs(nums,index+1);
aset.pop_back();
//当前子集不选nums[index]
dfs(nums,index+1);
}
};
方法三、根据子集元素个数分情况收集
子集中元素的个数可以是0,1,2...,nums.size()
对于每一种情况,可以用回溯来收集。
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsets(vector<int>& nums) {
//子集中元素的个数可以是0,1,2...,nums.size()
for(int count = 0; count <= nums.size();count++){
backtracking(nums,0,count);
}
return res;
}
//从nums中收集元素个数为total_count的子集
void backtracking(vector<int>& nums,int start,int total_count){
if(aset.size() == total_count){
res.push_back(aset);
return;
}
for(int i = start;i < nums.size();i++){
aset.push_back(nums[i]);
backtracking(nums,i+1,total_count);
aset.pop_back();
}
}
};
方法四、直接回溯法
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsets(vector<int>& nums) {
backtracking(nums,0);
return res;
}
void backtracking(vector<int>& nums,int start){
res.push_back(aset);//收集子集要放在前面,不然会遗漏
// if(start == nums.size()) //终止条件可不写,因为下面的遍历也是这个条件
// return;
for(int i = start ;i < nums.size();i++){
aset.push_back(nums[i]);
backtracking(nums,i+1);
aset.pop_back();
}
}
};
90.子集二
90. Subsets II
方法一、迭代法实现子集枚举
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> res;
vector<int> aset;
bool flag = true;
int n = nums.size();
int m = 1<<n;
for(int mask = 0;mask < m;mask++){
aset.clear();
flag = true;
for(int i = 0;i < n;i++){
if(mask & (1<<i)){
if(i > 0 && (mask&(1<<(i-1))) == 0 && nums[i]==nums[i-1]){
flag = false;
break;
}
aset.push_back(nums[i]);
}
}
if(flag)
res.push_back(aset);
}
return res;
}
};
方法二、递归法实现子集枚举
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
dfs(false,nums,0);
return res;
}
void dfs(bool choseLast,vector<int>& nums,int index){
if(index == nums.size()){
res.push_back(aset);
return;
}
dfs(false,nums,index+1);
if(!choseLast && index > 0 && nums[index] == nums[index-1])
return;
aset.push_back(nums[index]);
dfs(true,nums,index+1);
aset.pop_back();
}
};
方法三、根据子集元素个数分情况收集
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());//后面树层去重,需要先排序,让相等的元素相邻
int n = nums.size();
//子集中元素的个数可能是0,1,2,...n
for(int count = 0;count <=n;count++){
backtracking(nums,0,count);
}
return res;
}
void backtracking(vector<int>& nums,int start,int total_count){
if(aset.size() == total_count)
{
//子集中元素个数已经达到目标个数total_count
res.push_back(aset);
return;
}
for(int i = start;i < nums.size();i++){
if(i > start && nums[i] == nums[i-1])//树层去重,
continue;//可以把这里的循环理解为回溯树横向上不同子集的遍历,相同元素不跳过会导致重复收集之前收集过的答案
aset.push_back(nums[i]);
backtracking(nums,i+1,total_count);//这里的递归是对同一个子集的下一个元素的选取,同一个子集中是允许元素重复的。
aset.pop_back();
}
}
};
方法四、直接回溯法
收集回溯树的结点
class Solution {
vector<vector<int>> res;
vector<int> aset;
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
backtracking(nums,0);
return res;
}
void backtracking(vector<int>& nums,int start){
res.push_back(aset);
for(int i = start;i < nums.size();i++){
if(i>start && nums[i]==nums[i-1])
continue;
aset.push_back(nums[i]);
backtracking(nums,i+1);
aset.pop_back();
}
}
};