问题:输出$[0,1,2,3,...n)$的所有子集。
1. 增量构造法:一次选出一个元素放到集合中。由于$A$中的元素个数不确定,每次递归调用都要输出当前集合。另外,递归边界也不需要显示确定——如果无法继续添加元素,自然就不会递归了。
void print_subset(int n, int* A, int cur){ for(int i = 0; i < cur; i++) printf("%d ", A[i]); printf("\n"); int s = cur ? A[cur - 1] + 1 : 0; for(int i = s; i < n; ++i){ A[cur] = i; print_subset(n, A, cur + 1); } }
2. 位向量法:构造一个位向量$B[i]$,而不是直接构造子集$A$本身,其中$B[i]=1$,当且仅当$i$在子集$A$中。
void print_subset1(int n, int* B, int cur){ if(cur == n){ for(int i = 0; i < cur; ++i) if(B[i]) printf("%d ", i); printf("\n"); return; } B[cur] = 1; print_subset1(n, B, cur + 1); B[cur] = 0; print_subset1(n, B, cur + 1); }
3. 二进制法:当用二进制表示子集时,位运算中的按位与、或、异或对应集合的交、并和对称差。
输出子集$S$对应的各个元素:
void print_subset2(int n, int s){ for(int i = 0; i < n; ++i) if(s & (1 << i)) printf("%d ", i); printf("\n"); }
枚举子集:
for(int i = 0; i < (1 << n); ++i) print_subset2(n, i);
Leetcode 78. Subsets
给一个包含不同整数的集合,返回其所有子集。
方法1:(recursive)
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> subs; vector<int> sub; dfs(nums, 0, sub, subs); return subs; } void dfs(vector<int>& nums, int i, vector<int>& sub, vector<vector<int>>& subs){ subs.push_back(sub); for(int j = i; j < nums.size(); ++j){ sub.push_back(nums[j]); dfs(nums, j + 1, sub, subs); sub.pop_back(); } } };
方法2:位运算
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { int n = nums.size(); vector<vector<int>> res; for(int i = 0; i < (1 << n); ++i){ vector<int> cur; for(int j = 0; j < n; ++j){ if(i & (1 << j)) cur.push_back(nums[j]); } res.push_back(cur); } return res; } };
方法3:(iterative)
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> subs = {{}}; for (int num : nums) { int n = subs.size(); for (int i = 0; i < n; i++) { subs.push_back(subs[i]); subs.back().push_back(num); } } return subs; } };
Leetcode 90. Subsets II
给定一个集合,包含重复元素,返回其所有子集。
方法1:(iterative)
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { sort(nums.begin(), nums.end()); vector<vector<int>> res = {{}}; for(int i = 0; i < nums.size();){ int cnt = 0, num = nums[i]; while(i < nums.size() && nums[i] == num){ i++; cnt++; } int size = res.size(); for(int j = 0; j < size; ++j){ vector<int> tmp = res[j]; for(int k = 0; k < cnt; ++k){ tmp.push_back(num); res.push_back(tmp); } } } return res; } };
方法2:(recursive)
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { sort(nums.begin(), nums.end()); vector<vector<int>> subs; vector<int> sub; dfs(subs, sub, nums, 0); return subs; } void dfs(vector<vector<int>>& subs, vector<int>& sub, vector<int>& nums, int i){ subs.push_back(sub); for(int j = i; j < nums.size(); ++j){ if(j == i || nums[j] != nums[j - 1]){ sub.push_back(nums[j]); dfs(subs, sub, nums, j + 1); sub.pop_back(); } } } };