Given an array of integers nums
and an integer k
. A subarray is called nice if there are k
odd numbers on it.
Return the number of nice sub-arrays.
Example 1:
Input: nums = [1,1,2,1,1], k = 3 Output: 2 Explanation: The only sub-arrays with 3 odd numbers are [1,1,2,1] and [1,2,1,1].Example 2:
Input: nums = [2,4,6], k = 1 Output: 0 Explanation: There is no odd numbers in the array.Example 3:
Input: nums = [2,2,2,1,2,2,1,2,2,2], k = 2 Output: 16
统计优美子数组。题意是给你一个整数数组 nums 和一个整数 k。如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。请返回这个数组中「优美子数组」的数目。
子数组的题一般可以试图往sliding window或者前缀和prefix sum上靠,本题我两种解法都给出。首先前缀和的思路是遍历input里面的每个数字,把他们的前缀和sum和出现次数加到hashmap里面,但是这一题跟560题的区别在于,560是在找一个特别的子数组的和K,而本题是在找有多少个包含K个奇数的子数组,他并不在意子数组的和或者长度是多少。所以思路是遇到奇数的时候可以把这个数字改成1,遇到偶数的时候可以把这个数字改成0。当累加prefix sum的时候,因为从0到当前位置的前缀和为sum,所以如果找到一个前缀和sum - K,则说明存在这样一个优美子数组。
时间O(n)
空间O(n)
Java实现
1 class Solution { 2 public int numberOfSubarrays(int[] nums, int k) { 3 int res = 0; 4 int sum = 0; 5 HashMap<Integer, Integer> map = new HashMap<>(); 6 map.put(0, 1); 7 for (int i = 0; i < nums.length; i++) { 8 sum += (nums[i] % 2 == 1) ? 1 : 0; 9 map.put(sum, map.getOrDefault(sum, 0) + 1); 10 res += map.getOrDefault(sum - k, 0); 11 } 12 return res; 13 } 14 }
滑动窗口的思路也比较直观。还是用76题的经典模板,有两个指针,一个start一个end。当end指针遍历到奇数的时候,K才--。当K = 0的时候,说明当前的窗口里面包含的奇数个数为K个了,此时试图移动start指针。如果当前start指针的位置上的数字是奇数的话,则K++。其他环节跟一般的滑动窗口的题的做法没有区别。
时间O(n)
空间O(1)
Java实现
1 class Solution { 2 public int numberOfSubarrays(int[] nums, int k) { 3 int start = 0; 4 int end = 0; 5 int res = 0; 6 int count = 0; 7 while (end < nums.length) { 8 if (nums[end] % 2 == 1) { 9 k--; 10 count = 0; 11 } 12 while (k == 0) { 13 if (nums[start] % 2 == 1) { 14 k++; 15 } 16 start++; 17 count++; 18 } 19 res += count; 20 end++; 21 } 22 return res; 23 } 24 }
既然题目说找的是恰好K个奇数数字的子数组,那么我们可以沿用992题的思路。即最多K个奇数数字的子数组 - 最多K - 1个奇数数字的子数组 = 正好K个奇数的子数组。
时间O(n)
空间O(n)
Java实现
1 class Solution { 2 public int numberOfSubarrays(int[] nums, int k) { 3 return helper(nums, k) - helper(nums, k - 1); 4 } 5 6 private int helper(int[] nums, int k) { 7 int start = 0; 8 int end = 0; 9 int res = 0; 10 while (end < nums.length) { 11 if (nums[end] % 2 == 1) { 12 k--; 13 } 14 end++; 15 while (k < 0) { 16 if (nums[start] % 2 == 1) { 17 k++; 18 } 19 start++; 20 } 21 res += end - start + 1; 22 } 23 return res; 24 } 25 }