3097. 或值至少为 K 的最短子数组 II
给你一个 非负 整数数组 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* 数组长度)
2447. 最大公因数等于 K 的子数组数目
给你一个整数数组 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;}
};