Files
cpp-flashcards/org/questions/subarray-patterns.org
T

4.8 KiB

Subarray Sum — Pattern Recognition Guide

Core Trigger: Subarray + Sum

When you see "subarray" and "sum" in the same problem description, Prefix Sums should almost always be your immediate first thought.

The fundamental formula:

Sum(i..j) = PrefixSum[j] - PrefixSum[i-1]

This algebraic rewrite turns a range query into a difference between two points. It completely eliminates the need to re-scan the array.

The mental trigger is simple: subarray + sum → prefix sums. Always.

Variations of this pattern:

  • "Count of subarrays where sum equals K": Use the hash map approach, looking for `current_sum - K`.
  • "Longest/Shortest subarray where sum equals K": Instead of storing the frequency of the prefix sum in your map, store its first seen index (`map[prefix_sum] = index`). This lets you track length via `current_index - map[current_sum - K]`.
  • "Subarray sum divisible by K": Store `prefix_sum % K` in your hash map instead of the raw sum.

The Multiplicative Variant: Subarray + Product

If the problem asks for a subarray product (e.g., "number of subarrays where product equals K"), the prefix sum pattern translates directly into a Prefix Product:

Product(i..j) = PrefixProduct[j] / PrefixProduct[i-1]

Instead of subtracting, you divide.

Edge case: Zeros reset the product to 0. Division by zero breaks the pattern. Handle by:

  1. Segmentation — split the array at zeros, solve each segment independently
  2. Track position of last seen zero to reset boundaries

The Counter-Pattern: When Is It Not Prefix Sums?

While "subarray + sum" strongly hints at prefix sums, you need to look at the constraints and types of numbers to choose the absolute best tool.

If you see "Subarray + Sum" AND… The Real Pattern Is… Why?
All numbers are strictly positive (>= 0) and you need to find a target sum or max length. Sliding Window (Two Pointers) Because the window sum is monotonic (expanding always increases the sum; shrinking always decreases it). Sliding window optimizes space to O(1) compared to O(n) for prefix sums.
Numbers can be negative, or you need to find an exact target sum. Prefix Sum + Hash Map Monotonicity is broken. Adding an element could make the sum smaller, so sliding window fails. You must use a hash map to remember past states.
The array is constantly being updated (dynamic updates) between sum queries. Segment Tree or Fenwick Tree (BIT) A standard prefix sum array takes O(n) to update if an element changes. Segment/Fenwick trees drop update and query times to O(log n).

Generalizing the Concept: "Prefix State"

Don't limit this trick just to addition. The core philosophy of a prefix sum is accumulating history as you traverse linearly. You can use a hash map to track the "prefix state" for things that don't look like math at first.

Problem Mapping Reduces To
Equal 0s and 1s 0 → -1, 1 → +1 Subarray sum = 0
Equal odd/even even → +1, odd → -1 Subarray sum = 0
Equal vowels/consonants vowel → +1, consonant → -1 Subarray sum = 0
Equal A/B/C counts Track (c_A - c_B, c_B - c_C) Prefix state tuple repeats
Subarray product Prefix product Division (handle zeros)
Subarray XOR Prefix XOR XOR is invertible
Subarray sum Prefix sum Subtraction

The pattern:

  1. Define a state that accumulates as you traverse
  2. Find a way to "undo" or compare states (subtract, XOR, divide, compare tuples)
  3. Use a hash map to find when the same state (or target difference) appears

Summary Checklist

  1. Subarray + Sum + Negative Numbers → Prefix Sum + Hash Map
  2. Subarray + Sum + Only Positive Numbers → Sliding Window
  3. Subarray + Sum + Frequent Updates → Segment/Fenwick Tree