【问题描述】 1248. 统计「优美子数组」
给你一个整数数组 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. 滑动窗口
时间复杂度:O(N) 空间复杂度:O(N)
public int numberOfSubarrays(int[] nums, int k) {
int len = nums.length, res = 0, feed = 0, arr[] = new int[len + 2];
for(int i = 0; i < len; i ++) {
// if it is odd
if((nums[i] & 1) == 1) {
arr[++feed] = i;
}
}
// left border
arr[0] = -1;
// right border
arr[feed + 1] = len;
for(int i = 1; i + k < feed + 2; i ++) {
res += (arr[i] - arr[i - 1]) * (arr[i + k] - arr[i + k - 1]);
}
return res;
}
2. 双指针
计算前面的偶数个数,遍历时遇到偶数直接加进来就可以了
时间复杂度:O(N) 空间复杂度:O(1)
class Solution {
public int numberOfSubarrays(int[] nums, int k) {
if (nums == null || nums.length == 0 || nums.length < k) return 0;
// 双指针
int left = 0, right = 0;
int count = 0; // 连续子数组中奇数的个数
int res = 0;
int preEven = 0; // 记录第一个奇数前面的偶数个数
while (right < nums.length){
// 连续子数组中奇数个数不够
if (count < k){
if (nums[right] % 2 != 0) count++;
right++; // 移动右侧指针
}
// 连续子数组中奇数个数够了,看第一个奇数前面有多少个偶数
if (count == k) {
preEven = 0;
while (count == k){
res++;
if (nums[left] % 2 != 0) count--;
left++;
preEven++;
}
} else res += preEven; // 每次遇到 right 为偶数的时候就进行累加 相当于区间前面偶数个数 * 后面偶数个数
}
return res;
}
}
【总结】
1. 找规律题目 想好再动手
2. 数组思路 双指针 滑动窗口
参考链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays/solution/java-hua-dong-chuang-kou-xiang-jie-zhi-xing-yong-s/
参考链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays/solution/java-shuang-zhi-zhen-by-kelly2018/