Count Number of Nice Subarrays

Problem Statement
The task is to find the number of continuous subarrays in a given array of integers (nums) that contain exactly k odd numbers. These subarrays are termed as "nice" subarrays. The input to the function will be the array nums and the integer k. The output should be an integer representing how many such "nice" subarrays exist.
Examples
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 are no odd numbers in the array.
Example 3
Input:
nums = [2,2,2,1,2,2,1,2,2,2], k = 2
Output:
16
Constraints
1 <= nums.length <= 500001 <= nums[i] <= 10^51 <= k <= nums.length
Approach and Intuition
The problem involves analyzing subarrays for a specific count of odd numbers. Given the constraints and nature of the problem, a brute-force solution could be too slow, especially with large arrays. Here's an approach to solve the problem efficiently:
Transform the Problem:
Simplify the problem by focusing only on the odd numbers innums. Convertnumsinto a binary representation where1denotes an odd number and0denotes an even number.Use Prefix Sum and HashMap:
- The idea is to use a prefix sum to count odd numbers up to each index.
- Create a hashmap to store how many times each count of odd numbers has been seen as a prefix sum.
- For each element, calculate the current count of odd numbers using the prefix sum.
- The key insight is that if at some index
ithe prefix sum isp, and we have previously seenp-kxtimes (using the hashmap), then there arexsubarrays ending atiwhich havekodd numbers.
Iterate Through Nums:
- Initialize the hashmap with
{0: 1}to handle the case where a subarray with exactlykodd numbers starts from the beginning. - As you iterate through
nums, update the prefix sum based on whether the current number is odd. - For each updated prefix sum, calculate how many times the
(current prefix sum) - khas occurred, as it will give the count of subarrays ending at this position that are "nice".
- Initialize the hashmap with
Count "Nice" Subarrays:
- For each index, update the count of "nice" subarrays by adding the count found in the previous step.
- Also, update the hashmap to reflect the current prefix sum count.
Using the data from the examples:
- For
nums = [1,1,2,1,1]andk = 3, convert to[1,1,0,1,1]:- The prefix sums would be
[1, 2, 2, 3, 4]and you determine counts of reaching each prefix sum consideringk.
- The prefix sums would be
Considering this method is efficient and direct, it caters well to the constraints provided, specifically handling large arrays up to the length of 50,000.
Solutions
- C++
- Java
- Python
class Solution {
public:
int countKSubarrays(vector<int>& nums, int k) {
return atMostK(nums, k) - atMostK(nums, k - 1);
}
private:
int atMostK(vector<int>& nums, int k) {
int count = 0, result = 0, left = 0;
for (int right = 0; right < nums.size(); right++) {
count += nums[right] % 2;
while (count > k) {
count -= nums[left] % 2;
left++;
}
result += right - left + 1;
}
return result;
}
};
To efficiently compute the number of "nice" subarrays with k odd numbers in C++, the provided solution implements an approach based on the difference between scenarios when there are at most k odd numbers versus at most k-1 odd numbers.
- Begin by defining the
countKSubarraysfunction which relies on reusing the logic meant to calculate the count of subarrays with at mostkodd numbers by using the helper functionatMostK. - Implement the
atMostKfunction that will keep track ofcount, the number of odd numbers,result, the count of valid subarrays, andleft, a pointer used for indicating the start of a window. - Utilize a sliding window strategy:
- Incrementally expand the window to include more elements (
rightpointer), updating thecountof odd elements. - If the
countexceedsk, adjust theleftpointer to shrink the window until thecountis appropriate again. - Update the count of valid subarrays for each position of the
rightpointer, accumulating results using the expressionresult += right - left + 1to consider all subarrays ending atright.
- Incrementally expand the window to include more elements (
This solution is effective in determining the number of subarrays that exactly contain k odd numbers by leveraging direct subtraction between two conditions, ensuring optimal computation and clearer results through the difference of outcomes for k and k-1. This method is highly efficient, using a sliding window approach for a time complexity of O(n) where n is the number of elements in the input array, providing a significant advantage for large datasets.
class Solution {
public int countOddSubarrays(int[] arr, int k) {
return countAtMost(arr, k) - countAtMost(arr, k - 1);
}
private int countAtMost(int[] arr, int k) {
int countOdds = 0, result = 0, left = 0;
for (int right = 0; right < arr.length; right++) {
countOdds += arr[right] % 2;
// Adjust the left index so countOdds is at most k
while (countOdds > k) {
countOdds -= arr[left] % 2;
left++;
}
// Add the number of valid subarrays ending at right
result += right - left + 1;
}
return result;
}
}
This Java solution is designed to solve the problem of counting the number of subarrays with exactly k odd numbers. The code utilizes two major functions: countOddSubarrays and countAtMost.
Start by analyzing the
countOddSubarraysmethod. It leverages the operation of helper functioncountAtMostto find subarrays with at mostkodd numbers and subarrays with at mostk - 1odd numbers. The difference between these two counts gives the exact number of subarrays with exactlykodd numbers.Dive deeper into the
countAtMostmethod, which is a sliding window technique used to maintain a dynamic scope of subarray indices[left, right]. Here,countOddskeeps track of the number of odd numbers within the current window.- Iterate over the array using
rightas the moving boundary of the window. - Update the count of odd numbers
countOddsby checking if the current element is odd. - If
countOddsexceedsk, adjust theleftpoint of the window to reduce thecountOddsuntil it is at mostk. - For each position of
right, increment theresultby the number of valid subarrays ending atright, which is quantified by the gap betweenrightandleftplus one (i.e.,right - left + 1).
- Iterate over the array using
This method efficiently uses the sliding window concept, allowing the function to maintain an adaptive list of candidate subarrays while controlling the maximum allowed odd elements, resulting in an optimal calculation of the desired count of nice subarrays.
class Solution:
def countOddSubarrays(self, array: List[int], count: int) -> int:
return self.subarrayCountLessThanEqual(array, count) - self.subarrayCountLessThanEqual(array, count - 1)
def subarrayCountLessThanEqual(self, array: List[int], threshold: int) -> int:
odd_count, result, left = 0, 0, 0
for right in range(len(array)):
odd_count += array[right] % 2
while odd_count > threshold:
odd_count -= array[left] % 2
left += 1
result += right - left + 1
return result
This Python code defines a method to count the number of subarrays with a given number of odd elements in a list of integers. The solution uses the two-pointer technique to efficiently find the desired subarrays.
The
countOddSubarraysfunction calculates the difference between:- The number of subarrays with odd counts less than or equal to
count - The number of subarrays with odd counts less than
count
This difference effectively returns the number of subarrays that have exactly
countodd numbers.- The number of subarrays with odd counts less than or equal to
The helper method
subarrayCountLessThanEqualefficiently counts how many subarrays have odd counts less than or equal to a specified thresholdthreshold. This is accomplished by using two variables,leftandright, to maintain a sliding window:- Increment
odd_countwhen an odd element is encountered as therightpointer advances. - If
odd_countexceeds thethreshold, increment theleftpointer to reduce theodd_count. - Add to the result the number of valid subarrays ending at the current
rightpointer.
- Increment
This systematic approach ensures optimal counting of the subarrays within the given constraints, using a combination of mathematical computation and efficient looping structures.