We need to count how many contiguous subarrays contain exactly k odd numbers. Only parity matters: each element is either odd or even, and the even numbers never affect whether a subarray qualifies.
If we strip away the even numbers and think about where the odd numbers sit, the problem becomes choosing windows that capture exactly k of them. Even numbers at the edges of such a window add flexibility, because the boundaries can extend through them without changing the odd count. That flexibility is what makes the answer larger than the number of odd-number groups alone.
This is an "exactly k" counting problem. Two standard techniques apply: count prefix odd-totals with a hash map (the same idea as subarray-sum counting), or compute "at most k" minus "at most k-1" with a sliding window.
1 <= nums.length <= 50000 - With n up to 50,000, we need O(n) or O(n log n). An O(n^2) brute force that checks every subarray would be 2.5 billion operations in the worst case, which is too slow.1 <= nums[i] <= 10^5 - Values are positive integers. We only care about whether each value is odd or even, so the actual magnitude doesn't matter.1 <= k <= nums.length - k is at least 1, so we're always looking for subarrays with at least one odd number.Check every possible subarray and count how many odd numbers it contains. If the count equals k, the subarray is nice.
For each starting index, extend the subarray one element at a time while maintaining a running count of odd numbers. Once the count exceeds k, every longer subarray with the same start also exceeds k, so the inner loop can stop early.
result = 0 to track the total count of nice subarrays.i from 0 to n - 1:oddCount = 0.j from i to n - 1:nums[j] is odd, increment oddCount.oddCount == k, increment result.oddCount > k, break the inner loop.result.Loading animation...
The repeated work is the re-scan: each starting index counts odd numbers from scratch. Tracking the cumulative count of odd numbers once removes that re-scan and brings the time down to O(n).
If we build a prefix sum where prefix[i] counts the number of odd numbers from the start of the array up to index i, then the number of odd numbers in any subarray nums[i..j] is prefix[j] - prefix[i-1]. So we need pairs where prefix[j] - prefix[i-1] = k, which means prefix[i-1] = prefix[j] - k.
As we iterate through the array, we maintain a hash map that stores how many times each prefix value has appeared. For each position j, we look up how many earlier positions had a prefix of prefix[j] - k. Each such position is the start of a distinct nice subarray ending at j, so we add that count to the result. Concretely, if 5 odd numbers have appeared by position j and k = 2, every earlier position with a prefix of 3 starts a nice subarray ending at j.
prefixCount map with {0: 1} (the empty prefix has 0 odd numbers, and it occurs once).oddCount = 0 and result = 0.nums:oddCount.oddCount - k exists in the map, add its count to result.prefixCount[oddCount] by 1.result.Loading animation...
The prefix sum approach runs in O(n) time but spends O(n) space on the hash map. A sliding window achieves the same time bound with constant space.
Counting subarrays with exactly k odd numbers directly with a sliding window is awkward, because when the window holds exactly k, both expanding and shrinking can stay valid, so there is no single rule for moving the pointers. Counting subarrays with at most k odd numbers avoids this: expand the right end, and whenever the window has more than k odd numbers, shrink from the left. After the shrink, every subarray that ends at right and starts between left and right has at most k odd numbers, and there are right - left + 1 of them. Summing this at each step counts every valid subarray exactly once, at its right endpoint.
The identity exactly(k) = atMost(k) - atMost(k - 1) converts the easy count into the one we need. A subarray with at most k odd numbers has 0, 1, ..., or k of them; a subarray with at most k-1 has 0, 1, ..., or k-1. Subtracting cancels everything except the subarrays with exactly k odd numbers.
atMost(nums, k) that counts subarrays with at most k odd numbers:left and right starting at 0.right through the array. When nums[right] is odd, decrement k.k < 0, shrink from left until k >= 0 (incrementing k when nums[left] is odd).right - left + 1 to the count.atMost(nums, k) - atMost(nums, k - 1).Loading animation...
atMost twice, each doing a single pass through the array. Each pass is O(n) because the left pointer only moves forward. Total: O(2n) = O(n).