Pattern Recognition — Subarray Sum Equals K (LC560)

1. Identifying the Prefix Sum Pattern

This problem screams prefix sum combined with a hash map due to the following clues:

  • We need to find contiguous subarrays with a specific sum (k).
  • The array can include negative numbers, making simple sliding windows tricky.
  • The goal is to count all valid subarrays, not just one, suggesting a cumulative approach.

2. What is a Prefix Sum?

A prefix sum at index i is the sum of all elements from the start of the array up to index i. For nums = [1,2,3]:

Index:     0  1  2
Array:    [1, 2, 3]
PrefixSum:[0, 1, 3, 6] (0 is before index 0)
  

To find the sum of subarray [i,j], compute prefixSum[j] - prefixSum[i-1]. If this equals k, we’ve found a valid subarray.

3. Why Hash Map with Prefix Sums?

Instead of recomputing sums for every possible subarray (O(n²)), we use a hash map to store prefix sums and their frequencies. For each index j, we check if prefixSum[j] - k exists in the map, indicating a subarray with sum k.

nums = [1,1,1], k = 2
PrefixSum: [0,1,2,3]

At index 1: prefixSum=2
  Check if (2-2)=0 exists in map -> Yes (before index 0)
  Subarray [1,1] (indices 0-1) works.

At index 2: prefixSum=3
  Check if (3-2)=1 exists in map -> Yes (at index 0)
  Subarray [1,1] (indices 1-2) works.
  

4. Step-by-Step Recognition Checklist

  • Problem asks for subarrays with a specific sum? ✅
  • Array includes negative numbers or zeros? ✅ (Rules out simple sliding window)
  • Need to count all valid subarrays, not just one? ✅
  • If yes, consider prefix sum + hash map for O(n) solution.

5. Comparison with Other Patterns

Problem Pattern Type Technique Key Condition
Two Sum Hash Map Single pass, check complement Find pair with sum = target
Longest Substring Without Repeating Characters Sliding Window Expand/shrink window No repeating chars
Minimum Window Substring Variable-Size Sliding Window Expand/shrink with frequency map Contains all chars of target
Subarray Sum Equals K (LC560) Prefix Sum + Hash Map Track prefix sums, check difference Subarray sum equals k

6. Beginner-Friendly Tips

  • Draw the array and compute prefix sums manually to see how they work.
  • Use a hash map to store prefixSum -> count to track how many times a sum occurs.
  • Think of the problem as finding pairs of prefix sums where their difference equals k.
  • Unlike sliding window, prefix sums handle negative numbers seamlessly.

7. Key Keywords That Hint Prefix Sum

Look for phrases in problem statements:

  • "contiguous subarray"
  • "sum equals k"
  • "count all subarrays"
  • "negative numbers allowed"

Interview-Focused — Short Answer to Deliver (Subarray Sum Equals K)

"For Subarray Sum Equals K, a brute-force approach checks all subarrays, taking O(n²) time. Instead, I’ll use a prefix sum with a hash map: track cumulative sums and store their frequencies in a map. For each index, check if prefixSum - k exists in the map to count valid subarrays. This gives O(n) time and O(n) space. I’ll handle edge cases like negative numbers, zeros, and empty subarrays by initializing the map with a zero sum."

One-Minute Checklist to Say

  • Explain brute-force (all subarrays) and why it’s slow: O(n²).
  • Describe prefix sum + hash map approach and its O(n) time complexity.
  • Dry-run a small example (e.g., [1,1,1], k=2).
  • Mention edge cases: negative numbers, zeros, and single-element subarrays.

Interview Script & What to Say (Subarray Sum Equals K)

Step-by-Step Script (Word-for-Word Suggestions)

  1. "Let me restate: given an array nums and integer k, I need to count all contiguous subarrays with sum k. Can I assume the array is non-empty, and does k include negative numbers?"
  2. "A brute-force solution checks every subarray by iterating over all start and end indices, computing sums in O(n²). This is correct but too slow for large arrays."
  3. "A better approach uses prefix sums with a hash map. I’ll compute the cumulative sum at each index and store the frequency of each sum in a map. For each index j, if prefixSum[j] - k exists in the map, it means there’s a subarray ending at j with sum k. This runs in O(n) time and O(n) space."
  4. "Let’s dry-run with nums = [1,1,1], k = 2: prefix sums are [0,1,2,3]. At index 1, prefixSum=2, check 2-2=0 (found, count=1). At index 2, prefixSum=3, check 3-2=1 (found, count=1). Total count is 2."
  5. "Edge cases: handle negative numbers and zeros in nums or k, initialize map with {0:1} for subarrays starting at index 0, and ensure empty arrays return 0."

What the Interviewer Hears

  • Clear understanding of the problem and constraints.
  • Ability to start with a brute-force baseline and optimize using prefix sums and hash map.
  • Confident dry-run with a concrete example, showing step-by-step logic.
  • Proactive handling of edge cases and clear complexity analysis.

Solution Approach — Subarray Sum Equals K (LC560)

1. Problem Restatement

Find the number of contiguous subarrays in nums with sum equal to k. Example: nums = [1,1,1], k = 2 → Output: 2 (subarrays [1,1] at indices 0-1 and 1-2).

2. Core Idea

  • Use prefix sums to compute the sum of any subarray efficiently.
  • Maintain a hash map to store the frequency of each prefix sum.
  • For each index j, check if prefixSum[j] - k exists in the map to count valid subarrays ending at j.
  • Initialize the map with {0:1} to handle subarrays starting from index 0.

3. ASCII Prefix Sum Flow

nums = [1,1,1], k = 2
Index:     0  1  2
Array:    [1, 1, 1]
PrefixSum:[0, 1, 2, 3]

Step 1: Initialize map = {0:1}
Step 2: At index 0, prefixSum=1
  - Check prefixSum-k = 1-2 = -1 (not in map)
  - Add prefixSum to map: {0:1, 1:1}
Step 3: At index 1, prefixSum=2
  - Check prefixSum-k = 2-2 = 0 (in map, count += 1)
  - Add prefixSum to map: {0:1, 1:1, 2:1}
Step 4: At index 2, prefixSum=3
  - Check prefixSum-k = 3-2 = 1 (in map, count += 1)
  - Add prefixSum to map: {0:1, 1:1, 2:1, 3:1}
Result: count = 2
  

4. JavaScript Step-by-Step Dry Run


// Input: nums = [1,1,1], k = 2
let map = new Map([[0, 1]]); // Initialize with sum=0 having frequency 1
let prefixSum = 0;
let count = 0;

// Iterate through the array
for (let i = 0; i < nums.length; i++) {
  prefixSum += nums[i]; // Update cumulative sum

  // If (prefixSum - k) exists in map, add its frequency to count
  if (map.has(prefixSum - k)) {
    count += map.get(prefixSum - k);
  }

  // Update map with current prefixSum
  map.set(prefixSum, (map.get(prefixSum) || 0) + 1);
}

console.log(count); // Output: 2
  

5. Step-by-Step Explanation

  1. Initialize a hash map with {0:1} to account for subarrays starting from index 0.
  2. Iterate through nums, computing the prefix sum at each index.
  3. For each prefix sum, check if prefixSum - k exists in the map. If it does, add its frequency to the count of valid subarrays.
  4. Update the map with the current prefix sum’s frequency.
  5. Return the total count of valid subarrays.

6. Key Beginner Takeaways

  • Prefix sums turn subarray sum queries into simple subtractions.
  • The hash map stores the frequency of prefix sums to count all valid subarrays efficiently.
  • Initializing map[0] = 1 is critical for subarrays starting at index 0.
  • This approach handles negative numbers and zeros naturally, unlike sliding window techniques.

Deep Dive — Subarray Sum Equals K (LC560)

1. Correctness Invariant

At each index j, the prefix sum represents the sum of elements from index 0 to j. If prefixSum[j] - k exists in the map, there is a subarray ending at j with sum k. The map ensures we count all such subarrays by tracking the frequency of previous prefix sums.

2. Why Prefix Sum + Hash Map Works

  • Prefix sums allow us to compute subarray sums in O(1) via subtraction.
  • The hash map stores prefixSum -> frequency, enabling us to count all subarrays ending at the current index in O(1).
  • Initializing map[0] = 1 ensures we capture subarrays starting from index 0 when prefixSum == k.

3. Variants & Trade-Offs

  • Find subarrays instead of counting: Store start/end indices in the map instead of frequencies.
  • Streaming input: Process elements one at a time, maintaining the map dynamically.
  • Large numbers: Use a Map in JavaScript to avoid precision issues with large prefix sums.
  • Space optimization: If memory is constrained, consider a two-pointer approach for positive numbers only, though less general.

4. Micro-Optimizations

  • Use Map instead of a plain object for reliable key handling with negative or large numbers.
  • Update the map after checking for prefixSum - k to avoid counting the current prefix sum prematurely.
  • Early exit if the array is empty or no valid subarrays are possible (rare due to problem constraints).

5. Proof Sketch

For any subarray [i,j] with sum k, we have prefixSum[j] - prefixSum[i-1] = k. Rearranging, prefixSum[j] - k = prefixSum[i-1]. By storing all prefix sums in a map, we ensure that at index j, we can find all previous indices i-1 where the difference equals k. The map’s frequency count ensures we capture all valid subarrays. No valid subarrays are missed because we process every index and check all possible differences.

6. Beginner Takeaways

  • The prefix sum pattern is powerful for subarray sum problems, especially with negative numbers.
  • The hash map reduces the problem to finding pairs of sums, similar to Two Sum but for cumulative sums.
  • Always initialize the map with {0:1} to handle edge cases.
  • Use ASCII diagrams to visualize prefix sums and subarray boundaries.

Common Pitfalls — Subarray Sum Equals K

1. Forgetting to Initialize Map with {0:1}

Without initializing the map with {0:1}, subarrays starting from index 0 (where prefixSum == k) are missed.

Example:
nums = [2], k = 2
Without map[0]=1, prefixSum=2 at index 0 won’t find a match, missing the subarray [2].
  

2. Updating Map Before Checking

Adding the current prefix sum to the map before checking prefixSum - k can lead to counting invalid subarrays (including the current element incorrectly).

Wrong:
map.set(prefixSum, (map.get(prefixSum) || 0) + 1);
if (map.has(prefixSum - k)) count += map.get(prefixSum - k);

Correct:
if (map.has(prefixSum - k)) count += map.get(prefixSum - k);
map.set(prefixSum, (map.get(prefixSum) || 0) + 1);
  

3. Assuming Positive Numbers Only

Beginners may assume a sliding window works because nums contains only positive numbers, but the problem allows negatives and zeros, requiring prefix sums.

4. Incorrect Prefix Sum Calculation

Forgetting to handle the cumulative sum correctly or misinterpreting indices can lead to off-by-one errors or wrong subarray sums.

Example:
nums = [1,2,3]
Incorrect prefixSum: [1,3,6] (missing 0 at start)
Correct: [0,1,3,6]
  

5. Using Object Instead of Map in JavaScript

Using a plain object for the hash map can cause issues with negative or large numbers as keys, as objects convert keys to strings.

6. Beginner Tips

  • Always dry-run with a small example like [1,1,1], k=2 to verify prefix sum logic.
  • Use ASCII diagrams to track prefix sums and map updates.
  • Check the order of map operations: query first, then update.
  • Test with negative numbers and zeros to ensure robustness.
a

Edge Cases — Subarray Sum Equals K

1. Single-Element Array

If the array has one element, check if it equals k.

Example:
nums = [2], k = 2 → Output: 1 ([2])
nums = [2], k = 3 → Output: 0
  

2. Empty Array

If the array is empty, return 0 since no subarrays are possible.

nums = [], k = any → Output: 0
  

3. Negative Numbers in Array or k

The array or k can include negative numbers, so the solution must handle them.

nums = [1,-1,0], k = 0
Output: 2 ([1,-1], [0])
  

4. Zero as k

When k = 0, we need subarrays with sum 0, which can include single zeros or pairs like [1,-1].

nums = [1,-1,0], k = 0
Output: 2
  

5. Multiple Valid Subarrays at Same Prefix Sum

Multiple subarrays may end at the same index with sum k, requiring the map to track frequencies.

nums = [1,1,1,1], k = 2
PrefixSum: [0,1,2,3,4]
At index 2: prefixSum=3, check 3-2=1 (count=1)
At index 3: prefixSum=4, check 4-2=2 (count=2)
Output: 3
  

6. Large Prefix Sums

Prefix sums can become very large (or negative) due to constraints, so use a Map to handle keys properly.

Interview Demonstration Tips

  • Draw prefix sum array and map updates on the whiteboard for clarity.
  • Run a small example like [1,1,1], k=2 to show prefix sum logic.
  • Explicitly mention initializing map[0]=1 for subarrays starting at index 0.
  • Highlight handling of negatives and zeros to show robustness.

Time & Space Complexity — Subarray Sum Equals K

1. Brute-Force Approach

Check every possible subarray by iterating over all start and end indices, computing the sum each time.

for i = 0 to n-1:
  for j = i to n-1:
    sum = nums[i] + ... + nums[j]
    if sum == k: count++
  
  • Time Complexity: O(n²) — nested loops over all subarrays.
  • Space Complexity: O(1) — only stores the count.
  • Interview Note: Mention to show correctness but highlight inefficiency.

2. Prefix Sum Without Hash Map

Compute prefix sums and check all pairs of indices for prefixSum[j] - prefixSum[i-1] = k.

prefixSum = [0, nums[0], nums[0]+nums[1], ...]
for i = 0 to n:
  for j = i+1 to n:
    if prefixSum[j] - prefixSum[i] == k: count++
  
  • Time Complexity: O(n²) — still checks all pairs.
  • Space Complexity: O(n) for storing prefix sums.
  • Interview Note: Rarely used, but shows understanding of prefix sums.

3. Prefix Sum + Hash Map (Optimal)

Use a hash map to store prefix sum frequencies, checking prefixSum - k in O(1) per index.

map = {0:1}
prefixSum = 0
for i = 0 to n-1:
  prefixSum += nums[i]
  count += map[prefixSum - k] or 0
  map[prefixSum] += 1
  
  • Time Complexity: O(n) — single pass, O(1) map operations.
  • Space Complexity: O(n) — stores up to n prefix sums in the map.
  • Interview Note: Emphasize O(n) efficiency and handling of edge cases.

Summary Table

ApproachTimeSpaceNotes
Brute-Force O(n²) O(1) Correct but slow; good for explaining baseline.
Prefix Sum Pairs O(n²) O(n) Uses prefix sums but still inefficient.
Prefix Sum + Hash Map O(n) O(n) Optimal; handles all edge cases efficiently.

Interview Tips

  • Explain why prefix sum + hash map is optimal for negative numbers.
  • Show a dry-run with [1,1,1], k=2 to illustrate map updates.
  • Mention trade-offs: brute-force is simple but slow; hash map balances time and space.
  • Highlight initializing map[0]=1 to handle edge cases.

Language-Specific Notes

Implementation details for the Subarray Sum Equals K solution vary by language. Select to view optimizations.

FAQs — Subarray Sum Equals K (LC560)

1. What is a prefix sum?

A prefix sum at index i is the sum of all elements from index 0 to i. It helps compute subarray sums efficiently using subtraction: sum[i,j] = prefixSum[j] - prefixSum[i-1].

2. Why use a hash map with prefix sums?

The hash map stores the frequency of each prefix sum. When we find a prefix sum S, we check if S - k exists in the map to count subarrays with sum k ending at the current index.

3. Why initialize map with {0:1}?

This accounts for subarrays starting from index 0 where the prefix sum equals k. Without it, we’d miss these subarrays.

Example: nums = [2], k = 2
prefixSum = 2, check 2-2=0 → found in map[0]=1.
  

4. How to handle negative numbers?

Prefix sums work naturally with negative numbers, as subtraction still yields correct subarray sums. The hash map handles negative prefix sums as keys.

5. Common mistakes to avoid?

  • Not initializing map[0]=1.
  • Updating the map before checking prefixSum - k.
  • Assuming sliding window works (fails with negative numbers).
  • Using a plain object instead of Map for large/negative keys.

6. How to explain in interviews?

  1. Restate the problem: count subarrays with sum k.
  2. Mention brute-force (O(n²)) and why it’s slow.
  3. Explain prefix sum + hash map for O(n) solution.
  4. Dry-run with [1,1,1], k=2 using ASCII diagrams.
  5. Cover edge cases: negatives, zeros, single-element arrays.

7. Related patterns?

  • Prefix sums for subarray/range sum problems.
  • Hash map for frequency counting or complement finding (e.g., Two Sum).
  • Clues: “contiguous subarray”, “sum equals k”, “count all”.