9.17晚双周赛题
本题思路:首先数组中值的范围被限定在10e9之内,因此,我们就一定能够得到按位或的最大值不超过32位有符号数,或者这个范围在扩大一点也没事,对结果没有影响。
或运算,只要某一位是1,则或过后该位就变成1。因此,我们需要找到尽可能多的1。这道题很容易给人想到一个思路是从后往前遍历。因为如果你从前往后遍历,某一位为0,你不会知道在该位后面是否还有数能够贡献1,除非你已经达到了该长度的最大整型。因此,我们选择从后往前遍历。创建一个flag数组,存放32位1出现的位置,从0到32自然是递增的,我们需要做的就是尽可能让高位多出现1。依次从后遍历每一个数,flag[j]统计第j位是1的位置,j肯定大于i。也就是说,该数对于最大或的结果的第j位是有贡献的。flag的更新策略是如果当前数对第j位有贡献,且当前位的位置在flag值之前,或者flag未保存任何值,则更新。为保证长度最短,flag的值显然是越靠近当前i越好,所以我们按照上述的法则更新。
坑:一直没想明白这道题为什么最后减i,原来这里子数组的定义是从i开始的连续数组,读题目还是要注意吧,不然效率真的挺低的。
class Solution {
public:
vector<int> smallestSubarrays(vector<int>& nums) {
int n = nums.size();
vector<int> flag(32, -1);
vector<int> res(n, -1);
for(int i = n-1; i >= 0; --i) {
int far = i;
for(int j = 0; j < 32; ++j) {
if(nums[i] >> j & 1) {
flag[j] = i;
}
if(flag[j] != -1) {
far = max(far, flag[j]);
}
}
res[i] = far - i + 1;
}
return res;
}
};