题目
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集不能包含重复的子集。你可以按任意顺序返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
-
关于顺序
- 如果想要每个子集中的数字有序,在开始递归前先对原数组排序
- 如果想子集按照数字个数从小到大,选数字时先选择不选再选择选
-
法一:递归枚举,对每个元素都进行选或不选
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;//记录最终结果
vector<int> path;//记录每趟子集计算中的当前子集
subsets(path, nums,0, result);//初始从第一个数字开始选
return result;
}
void subsets(vector<int>& path, vector<int>& nums, int cur,vector<vector<int>> &result)
{
//如果判断完所有的数字就把当前子集加入结果中
if(cur==nums.size())
{
result.push_back(path);
return;
}
//如果不选当前数字
subsets(path,nums,cur+1, result);
//如果选择当前数字
path.push_back(nums[cur]);
subsets(path,nums,cur+1,result);
path.pop_back();//把path数组恢复原样
}
};
-
时间复杂度:O(2^n)
-
空间复杂度O(n)
-
思路
- 对每个元素都选择要或不要,每当pandasn个元素后,将当前path中的数据存储到结果中
-
法二:位向量法,递归枚举,使用bool数组记录选择
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;//记录结果
vector<bool> selected(nums.size(),false);//记录是否使用当前数字
subsets(selected, nums,0, result);
return result;
}
//依次对每个数字做选择,全部数字选择完后将子集记录到结果中
void subsets(vector<bool>& selected, vector<int>& nums, int cur,vector<vector<int>> &result)
{
if(cur==nums.size())//记录当前子集
{
vector<int> path;
//将selected中的数据转化为当前子集
for(int i=0;i<nums.size();i++)
if(selected[i]==true) path.push_back(nums[i]);
result.push_back(path);
return;
}
selected[cur] = true;//选择当前数字,递归调用挑选下一个数字
subsets(selected,nums,cur+1, result);
selected[cur] = false;//不选择当前数字,递归调用挑选下一个数字
subsets(selected,nums,cur+1,result);
}
};
-
时间复杂度:O(2^n)
-
空间复杂度O(n)
-
该方法只能在没有重复数字时使用
-
法三:二进制法,即位向量法的迭代版
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;
vector<int> subset;
int n=nums.size();
for(int i=0; i<(1<<n); i++)//1<<n表示子集的个数
{
for(int j=0; j<n; j++)//依次将每一个int转化为一个子集
{
if(i&(1<<j)) subset.push_back(nums[j]);
}
result.push_back(subset);//子集加入到结果中
subset.clear();//清空当前子集
}
return result;
}
};
- 时间复杂度O(2^n)
- 空间复杂度O(n)
- 思路
- 本方法的前提是:集合的元素个数不超过int类型的位数。
- 用一个int中的每一位表示对应数组中元素是否选择。每个元素选择要或不要,一共有2^n种选法,对应在int中比1<<n小的每一个数,都代表一种排列。然后对每一个int,在for循环中将它转化为一个子集