【问题描述】 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 oddif((nums[i] & 1) == 1) {arr[++feed] = i;}}// left borderarr[0] = -1;// right borderarr[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/