Given a set of distinct integers, S, return all possible subsets.
Note:
- Elements in a subset must be in non-descending order.
- The solution set must not contain duplicate subsets.
For example,
If S = [1,2,3]
, a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
分析:这道题是暴力枚举法很好的例子,代码可以作为以后其他变形题的模板。这里介绍递归和迭代两种方法,递归方法比较常见,迭代方法则巧妙些。
递归代码如下:
class Solution { public: vector<vector<int> > subsets(vector<int> &S) { vector<vector<int> > result; vector<int> path; sort(S.begin(), S.end()); get_subsets(result, path, S, 0); return result; } void get_subsets(vector<vector<int> > &result, vector<int> &path, vector<int> &S, int start){ if(start == S.size()){ result.push_back(path); return; } get_subsets(result, path, S, start+1); path.push_back(S[start]); get_subsets(result, path, S, start+1); path.pop_back(); } };
迭代法利用了数的二进制表示的特点,对于一个大小为n的set,其subset的个数是2^n,其生成过程可以抽象为一个长度为n的bit集合,如果ith bit位为1则选择set中的第i个元素,如果ith bit位为0则不选择set中的第i个元素。而上面所述的二进制数又对应于0到2^n - 1间的每一个整数。但这种方法的限制是n要小于等于32,否则subset的个数超过int的范围。
1 class Solution { 2 public: 3 vector<vector<int> > subsets(vector<int> &S) { 4 vector<vector<int> > result; 5 6 sort(S.begin(), S.end()); 7 8 for(int i = 0; i < 1<<S.size(); i++){ 9 vector<int> path; 10 for(int j = 0; j < S.size(); j++){ 11 if(i & 1<<j) path.push_back(S[j]); 12 } 13 result.push_back(path); 14 } 15 16 return result; 17 } 18 };
再加一种迭代方法,当增加一个元素时,当前的subsets可以用由上一轮生成的subsets增量产生,具体方法是在保存上一轮原有subsets的同时,对于每一个subsets将当前元素添加在每个subsets的末尾。代码如下:
class Solution { public: vector<vector<int> > subsets(vector<int> &S) { vector<vector<int> > result(1, vector<int>()); sort(S.begin(), S.end()); for(int i = 0; i < S.size(); i++){ int result_size = result.size(); for(int j = 0; j < result_size; j++){ result.push_back(result[j]); result.back().push_back(S[i]); } } return result; } };