diff --git a/org/questions/subarray-patterns.org b/org/questions/subarray-patterns.org new file mode 100644 index 0000000..723e61c --- /dev/null +++ b/org/questions/subarray-patterns.org @@ -0,0 +1,67 @@ +#+title: Subarray Sum — Pattern Recognition Guide +#+AUTHOR: Noramyll + +* 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**