11Prefix sumArrays and hashing

Prefix sum with a hash map

Count subarrays that add up to k, even with negative numbers: remember how often each running sum appeared.

Problem: LeetCode 560, Subarray Sum Equals K (Medium). Count the subarrays (contiguous, non-empty) whose numbers add up to k. Numbers can be negative, which is why a sliding window does not work here.

Example from the post: nums = [1, -1, 3, 1, 2], k = 3 → 4 (the subarrays [1, -1, 3], [3], [-1, 3, 1], [1, 2]). With k = 4 the answer is 2 ([1, -1, 3, 1] and [3, 1]).

The idea

A road trip: you want every stretch of exactly 5 km. At every town, ask your notebook: was the meter ever at now − 5? Each time it was, that's one stretch. The meter reading is the running sum; the notebook is a hash map.

Sum now − an earlier sum = the part between. So a subarray ending here adds up to k exactly when some earlier running sum equals sum - k. The hash map remembers how many times each running sum has appeared.

The walk

nums = [1, -1, 3, 1, 2], k = 3. Running sums, starting from the empty start: 0, 1, 0, 3, 4, 6.

sum nowearlier sum it needstimes seensubarray
302 (the empty start and after −1)[1, -1, 3] and [3]
411[-1, 3, 1]
631[1, 2]

Four pairs of sums 3 apart, four answers.

Pseudocode

Pseudocode · any language
function subarraySum(nums, k):
    seen = empty map  // sum -> times seen
    seen[0] = 1       // the empty start
    sum = 0
    count = 0
    for each x in nums:
        sum = sum + x
        count = count + seen[sum - k]
        seen[sum] = seen[sum] + 1
    return count

A sum not in the map counts as 0. Ask the map first, then add your sum to it.

The trap: the missing 0. A subarray that starts at index 0 needs an earlier sum of 0, so put it in first. Without seen[0] = 1 the example returns 3 and misses [1, -1, 3]; with it, all four are found.

Code

import java.util.*;

public class Solution {
    public static int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> seen = new HashMap<>(); // sum -> times seen
        seen.put(0, 1);                               // the empty start
        int sum = 0;
        int count = 0;
        for (int x : nums) {
            sum = sum + x;
            count = count + seen.getOrDefault(sum - k, 0);
            seen.put(sum, seen.getOrDefault(sum, 0) + 1);
        }
        return count;
    }
}

Complexity

  • Time: O(n). One pass; each map lookup and update is O(1) on average.
  • Space: O(n) for the map (up to n + 1 different running sums).
  • Checking every subarray instead takes O(n²) time.

How it was tested

All four versions were checked against a brute-force count on 3,017 inputs: 3,000 random arrays (length 0 to 12, values from small ranges up to −1000..1000) plus edge cases (empty, single element, all zeros, all equal, sorted, reversed, length 200 at the value limits). All agreed. Re-run on 31 October 2026: all four print 4, 2, 2 and 2 on the four examples in their main.

Practice

Try these in order. Open the worked example first if you got stuck on the slides.