DFS+剪枝
- DFS:深度优先搜索,可通过回溯筛选符合条件的子集;
- 剪枝:特定环境下,减去多余的枝节,减少递归次数,减小时间复杂度;
题目:统计按位或能得到最大值的子集数目
- 给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。
如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。
对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
示例 1:
输入:nums = [3,1]
输出:2
解释:子集按位或能得到的最大值是 3 。有 2 个子集按位或可以得到 3 :
- [3]
- [3,1]
示例 2:
输入:nums = [2,2,2]
输出:7
解释:[2,2,2] 的所有非空子集的按位或都可以得到 2 。总共有 23 - 1 = 7 个子集。
示例 3:
输入:nums = [3,2,1,5]
输出:6
解释:子集按位或可能的最大值是 7 。有 6 个子集按位或可以得到 7 :
- [3,5]
- [3,1,5]
- [3,2,5]
- [3,2,1,5]
- [2,5]
- [2,1,5]
1>读懂题
-
1.找出原数组中按位或最大值;
-
2.找出其中符合按位或等于数组最大值的子数组;
注意:其中子集是根据索引,不是根据元素值
即[2,2,2]中[null,2,2]和[2,null,2]都是[2,2],但被认为是两个子集 -
tips:按位或: a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
2>求按位或最大值
- 求按位或的值时,max的值只会变大,不可能变小,所以直接遍历数组求解即可;
3>剪枝
- 剪枝即减去多余枝节:
已知:求解按位或的值时之会变大不会变小;
且步骤二中已求解数组的按位或最大值
所以:当遍历到二叉树的某个节点满足按位或等于最大值 时,该节点的所以子节点都符合条件,ans+2^n;
结论:当遍历到满足条件的节点时,它的子节点不许再遍历,进行剪枝
4>DFS
- 进行深度搜索时,无非两种情况:
- 1.选择该索引指向的元素;
- 2.不选择该索引指向的元素
题解
class Solution {
public int ans = 0;
public int countMaxOrSubsets(int[] nums) {
int sum = 0;
for(int i : nums){
sum |= i;
}
dfs(nums,sum,0,0);
return ans;
}
private void dfs(int[] nums,int sum,int idx,int tmp){
if(tmp == sum){
ans += 1<<(nums.length-idx);
return;
}
//判断,是否超出数组长度,进行回溯
if(nums.length == idx){
return;
}
dfs(nums,sum,idx+1,nums[idx]|tmp);
dfs(nums,sum,idx+1,tmp);
}
}
结论
- 剪枝+DFS+按位或 yyds
声明
-
原作者:E.L.E
-
<本文章著作权归作者所有,商业转载请获得作者授权,非商业转载请注明出处>
-
<欢迎大家评论>