给你一个整数数组 nums 和一个整数 k。
如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目。
示例 1:
输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
示例 2:
输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。
示例 3:
输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16
提示:
- 1 <= nums.length <= 50000
- 1 <= nums[i] <= 10^5
- 1 <= k <= nums.length
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
基本思想
滑动窗口
- 从头到尾遍历数组,找到满足要求的最小子串
- 统计子串两端连续偶数的个数,例如右边 r 个,左边 l 个,那么由当前最小子串构成的优美子数组有 (r + 1) x (l + 1) 个
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
//找到一个优美子数组向两端扩展,统计个数,用乘法的形式左面三个右面三个4x4
//然后再从第二个奇数所构成的优美数组向两端扩展
if(nums.size() == 0 || k > nums.size())
return 0;
int res = 0;
deque<int> pos;
int s = 0;//存储上一次最小优美子数组的最左面元素的下标的下一个位置,便于统计最小优美子数组的左面有几个偶数
for(int i = 0; i < nums.size(); ++i){
if(nums[i] & 1){
pos.push_back(i);//保存奇数的下标
}
if(pos.size() == k){
int l = pos.front() - s;//左面偶数的个数
int r = 0;
int k = i + 1;
//统计右面连续偶数的个数
while(k < nums.size() && ((nums[k] & 1) == 0)){
++r;
++k;
}
//cout << i << " " << l << " " << r << endl;
res += (l + 1) * (r + 1);
if(k == nums.size())
break;
s = pos.front() + 1;
pos.pop_front();
}
}
return res;
}
};
前缀和
- 统计以当前元素结尾的序列中优美子数组的个数
- 遍历数组的过程中,统计前 i 个数字中奇数的个数
- 如果奇数的个数 odd大于等于 k,需要统计前 i 个数字中有多少个奇数个数为odd - k的子序列,有几个就说明能构成几个优美子数组(这里不太好理解,参考:官方题解)
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
vector<int> cnt(nums.size() + 1, 0);
cnt[0] = 1;
int odd = 0;//统计前i个数中奇数的个数
int res = 0;
for(int i = 0; i < nums.size(); ++i){
odd += (nums[i] & 1);
res += ((odd >= k ? cnt[odd - k] : 0));
cnt[odd]++;
}
return res;
}
};
另一种写法:
- 用map统计前 i 个字符中奇数的个数,个数作为键,有几个这样的子序列作为值
- 遍历的过程中,统计目前为止奇数的个数,并借助map查找前缀中有几个序列中有sum - k个奇数
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
unordered_map<int, int> m;
int sum = 0;
m[0] = 1;
int cnt = 0;
for(int i = 0; i < nums.size(); ++i){
if(nums[i] % 2)
++sum;
if(m.count(sum - k))
cnt += m[sum - k];
++m[sum];
}
return cnt;
}
};