78. Subsets和90. Subsets II
目录
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,...nfor(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_countres.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();}}
};