1.题目描述
给定一个整数数组 arr,返回所有 arr 的非空子数组的不同按位或的数量。
子数组的按位或是子数组中每个整数的按位或。含有一个整数的子数组的按位或就是该整数。
子数组 是数组内连续的非空元素序列。
示例 1:
输入: arr = [0]
输出: 1
解释:
只有一个可能的结果 0 。
示例 2:
输入: arr = [1,1,2]
输出: 3
解释:
可能的子数组为 [1],[1],[2],[1, 1],[1, 2],[1, 1, 2]。
产生的结果为 1,1,2,1,3,3 。
有三个唯一值,所以答案是 3 。
示例 3:
输入: arr = [1,2,4]
输出: 6
解释:
可能的结果是 1,2,3,4,6,以及 7 。
2.解题思路
核心是维护 “以当前元素结尾的子数组的按位或结果集合” ,利用其数量有限的特点降低时间复杂度(最终时间复杂度 O(n*32),即线性复杂度),步骤如下:
-
初始化两个集合:
global_set:存储所有子数组按位或的不同结果(最终统计其大小);cur_set:存储以当前元素arr[i]结尾的所有子数组的按位或结果(最多 32 个值)。
-
遍历数组中的每个元素
arr[i]:- 新建临时集合
tmp_set,先加入arr[i](对应子数组[arr[i]],长度为 1 的子数组); - 遍历
cur_set中的每个值val,计算val | arr[i]并加入tmp_set(对应子数组arr[j...i],j < i,即把以arr[i-1]结尾的子数组扩展到arr[i]); - 将
tmp_set去重后赋值给cur_set(避免重复值,减少计算); - 将
cur_set中的所有值加入global_set(收集所有可能的结果)。
- 新建临时集合
-
遍历结束后,
global_set的大小就是答案。
3.代码实现
class Solution {
public:
int subarrayBitwiseORs(vector<int>& arr) {
unordered_set<int> global_set;//存储所有不同的按位或结果
unordered_set<int> cur_set;//存储以当前元素结尾的子数组的按位或结果
for(int num:arr){
unordered_set<int> tmp_set;
//1.加入当前元素自身
tmp_set.insert(num);
//2.将上一轮的cur_set中的值与当前num按位或,加入tmp_set
for(int val : cur_set){
tmp_set.insert(val | num);
}
//3.更新cur_set为当前tmp_set
cur_set = move(tmp_set);
//4.将当前cur_set的所有值加入全局集合
global_set.insert(cur_set.begin(),cur_set.end());
}
return global_set.size();
}
};