Turn every contiguous range into a difference between two prefix sums. As you scan, ask whether the prefix you need has already appeared.
Count the prefix you need before recording the prefix you have.
Let prefix[i] be the sum through index i. A subarray ending here sums to k exactly when an earlier prefix equals current - k. The map remembers how many earlier starting points can make that equation true.
Try the canonical [1, 1, 1] with k = 2. The trace exposes the needed prefix, the map of earlier frequencies, and the running answer.
0 occurring once: the empty prefix gives a subarray that starts at index 0.def subarraySum(nums, k):
frequencies = {0: 1} # empty prefix before index 0
prefix = answer = 0
for value in nums:
prefix += value
answer += frequencies.get(prefix - k, 0)
frequencies[prefix] = frequencies.get(prefix, 0) + 1
return answer
The initial {0: 1} represents the prefix before the array. It is what counts a valid range beginning at index 0.
S[j]Sum through the current right endpoint j.S[j] − kAn earlier prefix with this value makes the difference exactly k.count[S[j] − k]Each occurrence is one distinct left boundary, so add the count rather than just one.The prefix sequence is 0, 1, 2, 3. At prefix 2, the needed value is 0; at prefix 3, it is 1, which has appeared once. Those are the two length-2 windows.
Repeated prefix sums are useful: prefix 0 appears before the array, after [1,-1], and after the final 0. Their frequencies count all three valid subarrays.
“I represent a subarray sum as the difference of two prefix sums. While scanning, I keep frequencies of prefixes from earlier positions. For the current sum S, every earlier S minus k gives one valid start, so I add that frequency before recording S. This counts each range once in linear time.”