--- title: 'Prefix Sum' description: 'Precomputed cumulative state for O(1) range queries.' --- ## The idea Precompute running totals once. Then any range sum costs O(1). Like mile markers on a highway. Distance from mile 30 to mile 80? Subtract: 80 − 30 = 50. You do not re-drive the road. **The formula:** `sum(i..j) = prefix[j + 1] - prefix[i]` ## The picture ```mermaid flowchart TD A["nums: 3 1 4 1 5"] --> B["prefix: 0 3 4 8 9 14"] B --> C["sum(1..3) = prefix[4] − prefix[1]
= 9 − 3 = 6"] C --> D["Check: 1 + 4 + 1 = 6 ✓"] style D fill:#2e7d32,color:#fff ``` The leading 0 matters. It makes ranges that start at index 0 work with no special case. ## Range Sum Query (LC 303) Pay O(n) once at build time. Answer every query in O(1). ```python from itertools import accumulate class NumArray: def __init__(self, nums: list[int]): self.prefix = [0] + list(accumulate(nums)) def sum_range(self, left: int, right: int) -> int: return self.prefix[right + 1] - self.prefix[left] ``` ## Prefix + Hashmap (LC 560 — Subarray Sum Equals K) The signature trick of this topic. The question flips: "Which subarrays sum to k?" becomes "At each point, how many *earlier* prefixes equal `current − k`?" Because: if `prefix[j] − prefix[i] = k`, the slice between them sums to k. ```mermaid flowchart LR A["Walk the array,
carry running sum"] --> B["Ask the map:
seen sum − k before?"] B --> C["Yes, m times →
add m to answer"] B --> D["Record current sum
in the map"] D --> A style C fill:#2e7d32,color:#fff ``` ```python from collections import defaultdict def subarray_sum(nums: list[int], k: int) -> int: count = 0 current = 0 seen = defaultdict(int) seen[0] = 1 # empty prefix — subarrays that start at 0 for n in nums: current += n count += seen[current - k] # ask first seen[current] += 1 # record after return count ``` **Order matters.** Ask before you record, or a subarray of length 0 counts itself when k = 0. ## Product variant (LC 238 — Product of Array Except Self) Same idea, two directions. Prefix products from the left, suffix products from the right. `answer[i] = left[i] × right[i]` — everything except i. ```python def product_except_self(nums: list[int]) -> list[int]: n = len(nums) result = [1] * n left = 1 for i in range(n): result[i] = left left *= nums[i] right = 1 for i in range(n - 1, -1, -1): result[i] *= right right *= nums[i] return result ``` ## Complexity | | Time | Space | |---|---|---| | Build | O(n) | O(n) | | Each range query | O(1) | — | | Prefix + hashmap | O(n) one pass | O(n) | ## Close-out ritual Before you submit, say out loud: 1. Time and space complexity. 2. One edge case trace: range starting at 0, k = 0 with zeros in the array, or negative numbers (this is why sliding window fails and prefix + hashmap wins). ## Plan problems **A-set:** LC 303 · 238 · 560 **B-set:** LC 525 · 974