给你一个 非负 整数数组 nums
和一个整数 k
。
如果一个数组中所有元素的按位或运算 OR
的值 至少 为 k
,那么我们称这个数组是 特别的 。
请你返回 nums
中 最短特别非空
子数组
的长度,如果特别子数组不存在,那么返回 -1
。
示例 1:
**输入:**nums = [1,2,3], k = 2
**输出:**1
解释:
子数组 [3]
的按位 OR
值为 3
,所以我们返回 1
。
示例 2:
**输入:**nums = [2,1,8], k = 10
**输出:**3
解释:
子数组 [2,1,8]
的按位 OR
值为 11
,所以我们返回 3
。
示例 3:
**输入:**nums = [1,2], k = 0
**输出:**1
解释:
子数组 [1]
的按位 OR
值为 1
,所以我们返回 1
。
提示:
1 <= nums.length <= 2 * 105
0 <= nums[i] <= 109
0 <= k <= 109
解析:
看了别人的 模板进行总结 一下:
在本题暴力的做法是 定左区间,搜索右区间 。在or是只可以变大。
由单调性可以知道。
反过来 我们可以假定区间的右端点,对区间 or运算的 左端点 进行更新。
这样子就缩小的区间。
class Solution {
public:
int minimumSubarrayLength(vector<int>& nums, int k) {
int ans = INT_MAX;
vector<pair<int,int>> ors;
for(int i = 0;i < nums.size();i++)
{
ors.emplace_back(0,i);
//cout <<ors.size()<<endl;
int j = 0;
for(auto &p : ors)
{
auto &[or_,left] = p;
or_ |= nums[i];
if(or_ >= k){
ans = min(ans,i - left + 1);//以i为右端点进行ans
}
if(ors[j].first == or_)
{
ors[j].second = left;
}
else{
ors[++j] = p;
}
}
// cout << j <<endl;
ors.resize(j+1);
//cout << ors.size()<<endl;
}
return ans == INT_MAX ?-1:ans;
}
};
时间复杂度 为 :O(n* 数组长度)
给你一个整数数组 nums
和一个整数 k
,请你统计并返回 nums
的子数组中元素的最大公因数等于 k
的子数组数目。
子数组 是数组中一个连续的非空序列。
数组的最大公因数 是能整除数组中所有元素的最大整数。
示例 1:
输入:nums = [9,3,1,2,6,3], k = 3
输出:4
解释:nums 的子数组中,以 3 作为最大公因数的子数组如下:
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
示例 2:
输入:nums = [4], k = 7
输出:0
解释:不存在以 7 作为最大公因数的子数组。
提示:
1 <= nums.length <= 1000
1 <= nums[i], k <= 109
解析:
这一题和上一题也是十分的相似。
首先nums[i] 要可以被k整除。
class Solution {
public:
int subarrayGCD(vector<int>& nums, int k) {
int res = 0,n = nums.size(), i0 = -1;
vector<pair<int,int>> a;
for(int i = 0;i < nums.size();i++)
{
if(nums[i] % k)
{
a.clear();
i0 = i;
continue;
}
a.push_back({nums[i],i});
int j = 0;
for(auto &p : a)
{
p.first = gcd(p.first,nums[i]);
if(a[j].first != p.first)
{
j++;
a[j] = p;
}
else{
a[j].second = p.second;
}
}
a.resize(j+1);
if(a[0].first == k){
res += a[0].second - i0;
}
}
return res;
}
};