描述 Description
Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example, If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
[Subsets]
分析 Analysis
方法1
搜索长度为n的子集时使用n重for循环。O(n^n),这个复杂度绝对的不行。
方法2
用回溯法。类似深度优先搜索。因为是子集,[1,2]和[2,1]一样,所以我们的每次递归的停止条件都是到nums[]中的最后一个元素,也即指定了树向下生长时子树结点大小小于父结点。

也可以使用子集树:


方法3
迭代法。类似广度优先搜索。如[1, 2, 3]生成子集的过程:
- Initially:
[[ ]] - Adding the first number to all the existed subsets:
[[], [1]]; - Adding the second number to all the existed subsets:
[[], [1], [2], [1, 2]]; - Adding the third number to all the existed subsets:
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]].
方法4
利用bitmap。对于子集来说,每个元素只有2种状态:在子集中,不在子集中。这刚好符合2进制,可以考虑使用bitmap的方法。
我们对每个元素一个bit:
0:在当前子集中
1:不在当前子集中
对于n个元素,一共有2^n种取法,这和子集数也是一致的。
示例:
0) 0 0 0 -> Dont take 3 , Dont take 2 , Dont take 1 = { }
1) 0 0 1 -> Dont take 3 , Dont take 2 , take 1 = {1 }
2) 0 1 0 -> Dont take 3 , take 2 , Dont take 1 = { 2 }
3) 0 1 1 -> Dont take 3 , take 2 , take 1 = { 1 , 2 }
4) 1 0 0 -> take 3 , Dont take 2 , Dont take 1 = { 3 }
5) 1 0 1 -> take 3 , Dont take 2 , take 1 = { 1 , 3 }
6) 1 1 0 -> take 3 , take 2 , Dont take 1 = { 2 , 3 }
7) 1 1 1 -> take 3 , take 2 , take 1 = { 1 , 2 , 3 }
刚好可以取尽所有元素。
也就是说,如果我们从 0 - 2^n - 1 (这里是从0-7)循环取值i,看每个值i中对应的1有哪些,如果1在第k个bit位上,就说明题目给定的数组nums中的元素nums[k]在这个子集i中。如i = 4 即 1 0 0 时,只有第2个位置为1,所以此子集中只有一个数num[2],即{3}。
算法复杂度O(n*2^n),一层循环从0到2^n种子集取法,二层循环看每个取法对应的2进制中的1的个数。
如果nums.size()特别大,在判断时候,检测到一个1,就去掉j中最后的1(通过j & (j - 1)),这样j == 0时就可以提前结束内层循环。但是nums.size()不可能特别大,大于32的话,子集数目就比最大4位整数还大,测试中也没有这么大的数,如果有的话就只能使用回溯了。
或者增加判断比j大的那个最大的1的位置,这样i就可以提前结束。
代码 Code
方法2:回溯
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> subs;
vector<int> sub;
genSubsets(nums, 0, sub, subs);
return subs;
}
void genSubsets(vector<int>& nums, int start, vector<int>& sub, vector<vector<int>>& subs) {
subs.push_back(sub);
for (int i = start; i < nums.size(); i++) {
sub.push_back(nums[i]);
genSubsets(nums, i + 1, sub, subs);
sub.pop_back();
}
}
};
方法3:迭代
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> subs(1, vector<int>());
for (int i = 0; i < nums.size(); i++) {
int n = subs.size();
for (int j = 0; j < n; j++) {
subs.push_back(subs[j]);
subs.back().push_back(nums[i]);
}
}
return subs;
}
};
方法4:bit操作
class Solution {
public:
vector<vector<int> > subsets(vector<int> &nums) {
// sort (nums.begin(), nums.end()); //不用排序,没有说结果要有序
int elem_num = nums.size();
int subset_num = 1 << elem_num; //pow (2, elem_num);
vector<vector<int> > subset_set (subset_num, vector<int>());
for (int j = 0; j < subset_num; j++)
for (int i = 0; i < elem_num; i++)
if ((j >> i) & 1)
subset_set[j].push_back (nums[i]);
return subset_set;
}
};