[位运算|状态压缩]leetcode 78 子集
1.题目
题目链接
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:
解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
2.分析
2.1.状态串
二进制字符串可以用来表示状态。例如,有编号为1,2,3,4,5的五个灯泡,那么第2个灯泡与第5个灯泡打开便可以记为01001,换算成十进制数便为9。
2.2.本题的状态
给出若干个数,我们要判断这些数是否在对应的“子集”中。对于样例而言,相应的状态便可以对应为:000[],001[3],010[2],011[2,3],100[1],101[1,3],110[1,2],111[1,2,3]。
2.3.如何遍历状态
即从000遍历到111,换算成十进制便是从0遍历到7。记输入的nums有n个数,因此遍历所有状态需要从0遍历到1 << n(算术左移):
int n = nums.size();
for(int i = 0; i < (1 << n); i++) {
}
2.4.如何取出每个状态对应的数
例如我们有nums=[1,2,3],状态串101,那么如何将1与3取出来?
可以遍历nums中各个数,比如遍历到3,此时“遍历”的状态便为001。做与运算,由于与运算只有两边某一位均为1时结果才不为0,因此这样就可以判断我们当前遍历到的数是否在该状态串对应的子集内。
for(int j = 0; j < n; j++) {
if(i & (1 << j)){
t.push_back(nums[j]);
}
}
3.代码
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
for(int i = 0; i < (1 << n); i++) {
t.clear();
for(int j = 0; j < n; j++) {
if(i & (1 << j)){
t.push_back(nums[j]);
}
}
ans.push_back(t);
}
return ans;
}
};