78. Subsets 求集合的子集
问题描述
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],
[]
]
思路
- 若nums的长度为n,则子集和数为 2n 个。类比位数为n的二进制码流,也是有 2n 种变化,所以可以尝试用位操作的方法。比如n=3时,则从 000 到 111共有8种变化(000,001,010,011,100,101,110,111), 0表示不选,1表示选中。
- 可采用回溯法,关于回溯法,可参考 算法入门6:回溯法. 对数组进行深度优先搜索。
算法描述
- 位操作法
- 若nums的长度为n,则遍历
2n
次,每次得到一个子集:i
- 将i看成二进制码流,判断每一位是0还是1,如果为1,则选中nums[i],从而得到一个子集tmp
- 将子集tmp保存进result
2。 返回result
- 若nums的长度为n,则遍历
2n
次,每次得到一个子集:i
- 回溯法
- 判断nums是否为空,为空直接返回
- 路径path初始化为空。
- 根据深度优先搜索(DFS),采用回溯法执行subsets_dfs(nums,0,path,result),得到result:
- 如果位置pos超过了数组长度,则返回
- 从pos处开始遍历数组nums:i
- 将nums[i]压栈进入路径path
- 将path压栈进入result
- 递归调用subsets_dfs(nums,i+1,path,result)
- pop path出栈,剔除nums[i],
代码
//78. Subsets
vector<vector<int>> subsets(vector<int>& nums)
{
int method =1;// 1为位操作的方法,2为回溯法
switch(method)
{
case 1:// 位操作
{
vector<vector<int>> result;
for(int i=0;i< 1<<nums.size();i++)
{
vector<int> tmp;
for(int j=0;j<nums.size();j++)
{
if(i & 1<<j)
{
tmp.push_back(nums[j]);
}
}
result.push_back(tmp);
}
return result;
}
case 2:// 回溯法
{
vector<vector<int>> result;
vector<int> path;
result.push_back(path);
if(nums.empty())
return result;
subsets_dfs(nums,0,path,result);
return result;
}
}
}
回溯法 深度优先搜索
void subsets_dfs(vector<int>& nums,int pos,vector<int>& path,vector<vector<int>>& result)
{
if(pos==nums.size())
return;
for(int i=pos;i<nums.size(); i++)
{
path.push_back(nums[i]);
result.push_back(path);
subsets_dfs(nums,i+1,path,result);
path.pop_back();
}
}