> https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/by-tong-zhu-mmeu/
思路1:不优化的回溯(穷举)
对于nums
的每个位置而言,都有两种状态,就是“选”或者“不选”,那么假设有位,就应当有
种选择方案,如果方案符合条件,就将其放入子集方案中,否则不放入。
对于回溯的树来讲,就是一颗二叉树,每个非叶子节点有两个分支,分别代表“选择”和“不选择”,第i
层的节点,就是nums[i]
,这样就可以通过dfs树来遍历。
脑子里面要有下面这张图
代码1:
class Solution {
public:
void dfs(int& count_subs, vector<int>& nums, int cur_depth, int num_size, int cur_or, int max_or) {
if (cur_depth == num_size) {
if (max_or == cur_or) {
count_subs++;
}
return;
}
// 选择当前节点,也就是树的左分支
dfs(count_subs, nums, cur_depth + 1, num_size, cur_or | nums[cur_depth], max_or);
// 不选择当前节点,也就是树的右分支
dfs(count_subs, nums, cur_depth + 1, num_size, cur_or , max_or);
}
int countMaxOrSubsets(vector<int>& nums) {
int count_subs = 0;
int max_or = 0;
for (int num : nums) {
max_or |= num;
}
dfs(count_subs, nums, 0, nums.size(), 0, max_or);
return count_subs;
}
};
思路2:回溯穷举(带剪枝)
可以对树进行剪枝。优化两点:1.树本身的结构不一样 2.加入了剪枝<br /> 首先,可以**通过树的叶子节点一定是数组的最后一个元素**这样的办法,来简化树的形状。<br /> 然后,统计最大的按位或的结果,也就是所有元素全部或一遍。得到`max_or`。<br /> 接着,遍历简化之后的那棵树,如果当前的按位或结果`cur_or`和`max_or`相等,那么,就说明剩下的所有元素都是可有可无的。剩下的元素一共`num_size - cur_depth`个,那么,对应的`cur_depth`下,一共应该有个子集。否则,就继续DFS遍历这棵树。<br />“以数组的最后一个数字作为叶子节点”和“二叉是否选择当前节点”的两棵树之间的异同:<br /><br />然后加上剪枝条件,提前返回就可以得到最优化的方案了。(两棵树本质上就是一棵树的两种呈现形式)
代码2:
class Solution {
public:
int count_subs = 0;
void dfs(vector<int>& nums, int cur_depth, int cur_or, int max_or) {
int num_size = nums.size();
if (cur_or == max_or) {
count_subs += (1 << (num_size - cur_depth));
return;
}
for (int i = cur_depth; i < num_size; ++i) {
dfs(nums, i + 1, cur_or | nums[i], max_or);
}
}
int countMaxOrSubsets(vector<int>& nums) {
int max_or = 0;
for (int num : nums) {
max_or |= num;
}
dfs(nums, 0, 0, max_or);
return count_subs;
}
};