Problem Statement
Count Number of Nice Subarrays
You are given a list of whole numbers called nums and a number k. A subarray is just a chunk of the list that sits next to each other, with no gaps. We call a subarray "nice" if it holds exactly k odd numbers. Your job is to count how many nice subarrays there are. Counting "exactly k" directly is fiddly, so we use a clever shortcut. Think of it like measuring water. If you want the amount between the 2 liter and 3 liter marks, you take "everything up to 3 liters" and subtract "everything up to 2 liters." Here we do the same with a trick called exactly(k) = atMost(k) - atMost(k-1). The word atMost(k) means "count of subarrays that have k odd numbers or fewer." Subtract the ones with too few, and what is left is exactly k. To count "at most k," we use a sliding window, which is a stretchy frame over the list that we grow on the right and shrink on the left to keep it valid.
Signals to notice
Brute force first
Check every subarray — O(n²).
The key insight
exactly(k) = atMost(k) - atMost(k-1). atMost(k): sliding window counting subarrays with ≤ k odd numbers. O(n).
Trace it on nums=[1,1,2,1,1], k=3
Goal: answer = atMost(3) - atMost(2). Odd values are the 1s at indices 0,1,3,4. atMost(3): r=0(1) odd=1, r=1(1) odd=2, r=2(2) odd=2 -> result grows 1,3,6 (window [0..r]) atMost(3): r=3(1) odd=3 ok, result += 4 -> 10; r=4(1) odd=4>3, shrink left to 1 (odd=3), result += 4 -> 14 atMost(3) = 14 atMost(2): r=0 odd=1, r=1 odd=2, r=2 odd=2 -> result 1,3,6 (no shrink yet) atMost(2): r=3(1) odd=3>2, shrink left->1 (odd=2), result += 3 -> 9 atMost(2): r=4(1) odd=3>2, shrink left->2 (odd=2), result += 3 -> 12; atMost(2) = 12 answer = atMost(3) - atMost(2) = 14 - 12 = 2
What must stay true
Replace 'odd' with a counter. atMost(k) counts subarrays with ≤ k odds using the standard window technique. Subtraction gives exactly k.
Shape of the loop
function atMost(k):
left = 0; odd = 0; result = 0
for right in 0..n-1:
if nums[right] is odd: odd += 1
while odd > k:
if nums[left] is odd: odd -= 1
left += 1
result += right - left + 1
return result
answer = atMost(k) - atMost(k-1)Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Same as Subarrays with K Different Integers — direct 'exactly k' counting is hard, but the subtraction trick makes it easy.