For each start, extend the end and count every time the running sum equals k.
Approach 1
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
int sum = 0;
for (int j = i; j < nums.length; j++) {
sum += nums[j];
if (sum == k) count++;
}
}
return count;
}
}
Verdict: 2 × 10⁸ steps at the limit: too slow. The repeated work is recomputing sums that prefix sums already know.
2
Optimal: prefix sums with a hash map
Time O(n) Space O(n)
Keep a running sum and a map of how often each prefix sum has occurred (seeded with 0 → 1). At each element, add seen[sum − k] to the count, then record sum.
▶ Dry run: Counting with prefix sumsnums = [1, 1, 1], k = 2
1
0
1
1
1
2
seen(map)
0 → 1
State(vars)
sum = 0count = 0
Step 1/4Seed: prefix sum 0 has been seen once (the empty prefix).
Approach 2
import java.util.HashMap;
import java.util.Map;
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> seen = new HashMap<>();
seen.put(0, 1);
int sum = 0, count = 0;
for (int x : nums) {
sum += x;
count += seen.getOrDefault(sum - k, 0);
seen.merge(sum, 1, Integer::sum);
}
return count;
}
}
Verdict: One pass. The canonical answer.
Before you submit
Edge cases and common mistakes
Test these inputs
k = 0 with zeros in the array
Negative numbers
The whole array sums to k
Mistakes people make
Using a sliding window (fails with negatives).
Forgetting the {0: 1} seed.
Recording sum before counting, which counts an empty subarray when k = 0.
Interview
Follow-up questions
How would you return the longest subarray with sum k instead?