题目
思路 位运算
根据题意模拟,求出子集,并判断子集的按位或是否和最大值相等。
代码
class Solution {
public:
int countMaxOrSubsets(vector<int>& nums) {
int res = 0;
for(int num : nums)
res |= num;
vector<vector<int>> subset;
vector<int> cur;
dfs(nums, 0, cur, subset);
int ans = 0;
for(int i = 0; i < subset.size(); i++){
int tmp = 0;
for(int j = 0; j < subset[i].size(); j++){
tmp |= subset[i][j];
}
if(tmp == res) ans++;
}
return ans;
}
void dfs(vector<int>& nums, int x, vector<int>& cur, vector<vector<int>>& ans){
if(x == nums.size()){
ans.push_back(cur);
return;
}
dfs(nums, x + 1, cur, ans);
cur.push_back(nums[x]);
dfs(nums, x + 1, cur, ans);
cur.pop_back();
}
};
思路 位运算
由于nums数组的大小小于等于16,所以可以用一个n个bit的整数表示对数组中每一个元素的取舍。
代码
class Solution {
public:
int countMaxOrSubsets(vector<int>& nums) {
int n = nums.size(), maxValue = 0, cnt = 0;
for(int i = 0; i < (1 << n); i++){
int tmp = 0;
for(int j = 0; j < n; j++){
if(i & (1 << j))
tmp |= nums[j];
}
if(maxValue == tmp){
cnt++;
}else if(maxValue < tmp){
cnt = 1;
maxValue = tmp;
}
}
return cnt;
}
};
思路 DFS
将每个子集的得分这一步融入枚举子集状态,通过回溯实现。
代码
class Solution {
public:
vector<int> nums;
int max = 0, ans = 0;
int countMaxOrSubsets(vector<int>& nums) {
this -> nums = nums;
dfs(0,0);
return ans;
}
void dfs(int u, int val){
if(u == nums.size()){
if(val == max){
ans++;
}else if(val > max){
max = val;
ans = 1;
}
return;
}
dfs(u + 1, val);
dfs(u + 1, val | nums[u]);
}
};
思路 状压DP
需要找到当前状态state可由那些状态转移而来:假设当前state中处于最低位的1位于第idx位,首先可以使用lowbit操作得到仅保留第idx的1所对应的数值,记为lowbit,那么对应的状态方程为:f[state] = f[state - lowbit] ^ nums[idx]。
代码
class Solution {
public:
int countMaxOrSubsets(vector<int>& nums) {
unordered_map<int,int> map;
for(int i = 0; i < 20; i++)
map[1 << i] = i;
int n = nums.size(), max = 0, ans = 0, mask = (1 << n);
vector<int> f(mask);
for(int i = 1; i < mask; i++){
int lowbit = i & -i;
int prev = i - lowbit, idx = map[lowbit];
f[i] = f[prev] | nums[idx];
if(f[i] > max){
max = f[i];
ans = 1;
}else if(f[i] == max){
ans++;
}
}
return ans;
}
};