3095. 或值至少 K 的最短子数组 I
3097. 或值至少为 K 的最短子数组 II
题解
class Solution {
public:
int minimumSubarrayLength(vector<int>& nums, int k) {
int ans = INT_MAX;
for (int i = 0; i < nums.size(); i++) {
int x = nums[i];
if (x >= k)
return 1;
// 窗口向前延伸,如果nums[j] | x == nums[j]
// 说明加上这个数和不加一样,所以跳过。
for (int j = i - 1; j >= 0 && (nums[j] | x) != nums[j]; j--) {
nums[j] |= x;
if (nums[j] >= k) {
ans = min(ans, i - j + 1);
break;
}
if (i - j + 1 >= ans - 1) // 剪枝
break;
}
}
return ans == INT_MAX ? -1 : ans;
}
};
思路
滑动窗口
该思路为什么适用?因为这一题有两个要求:最短、连续子数组。
从nums[i]向前遍历,并且直接对之前的数组值进行修改,将nums[j] |= nums[i],这里也利用的位运算的特性,如果换成是累加或者是累乘都不可用。这样只需要每次向前遍历的时候判断nums[j]与k的大小,一旦nums[j]>=k就表示该子数组满足要求,这时候只需要将子数组长度与ans比较,更新最终结果为较小的值即可。
对此,剪枝策略就是,如果往前遍历时,nums[j]并不会对最终结果造成影响(即(nums[j] | x) == nums[j],表示nums[j]加入按位或运算并不影响结果),那么就直接跳出子循环;另外,也可以对子数组长度进行剪枝,如果遍历时长度已经比ans大了,则直接跳出循环。