When to use prefix sums
Use prefix sums when you have:
- Many range-sum queries on data that does not change: "what is the total sales from day 12 to day 40?"
- A question about contiguous stretches that add up to a target: "how many subarrays sum to
k?", especially with negative numbers. - A running total that you need at every position, such as a balance after each transaction.
- Many range updates ("add 5 to every item from index 3 to 90") followed by one read of the final array. For that, use the reverse tool: a difference array.
Use something else when:
- The data changes between queries: a prefix array goes stale after every update. Use a Fenwick tree or segment tree.
- You only need one answer: a single loop is O(n) and needs no extra memory.
- The numbers are all positive and you need a stretch with an exact or bounded total: a sliding window uses O(1) memory.
- You want the maximum or minimum of a range: use a sparse table, segment tree or monotonic queue. Prefix sums only work for operations you can subtract, like addition.
There is no library to import for the core idea. A few languages have a running-total helper (see the real-world section), but a prefix array is a single loop.
How prefix sums work
A prefix sum is the total of the first i numbers. Store every one of them in an array once, and any range total is a subtraction.
prefix[0] = 0, andprefix[i] = prefix[i - 1] + nums[i - 1]. The sum fromlefttoright(both included) isprefix[right + 1] - prefix[left].
Why the subtraction works: prefix[right + 1] adds up everything up to right. prefix[left] adds up everything before left. Taking one from the other leaves exactly the range. The array has one extra slot at the front, a 0, so a range that starts at index 0 needs no special case.
Two more ideas build on it:
- Subarray sum equals
k. A stretch ending at the current number sums tokwhen the running total now, minus some earlier running total, equalsk. So keep a dictionary of how often each running total has appeared, and look uptotal - k. Start it with{0: 1}so stretches that begin at the start are counted. This works with negative numbers, where a sliding window breaks. - Difference arrays. This is the reverse of a prefix sum. To add
vto every item fromltor, dod[l] += vandd[r + 1] -= v: only two slots change. After all updates, take a running total ofdto get how much each position changed.
Try it
Pick one of the three techniques, then press Run and step through. The top row is your array and the bottom row is the helper array.
Prefix sums and difference arrays
Step 1 of 8 · Press Space to play, arrow keys to stepArray
Prefix sums (prefix[i] = sum of the first i numbers)
The task: answer "what is the sum from index 1 to 4?" quickly, even for many queries. First build the prefix sums in one pass.
- additions to build:
- 0
- work per query:
- -
Once the prefix sums are built, each range query is a single subtraction. The brute-force count shows how many additions it would take to add the range up each time.
Things to try:
- Range sum queries, "Sum of 1 to 4": for
1 4 2 5 3 6the prefix array becomes0 1 5 7 12 15 21after 6 additions. The sum of indexes 1 to 4 isprefix[5] - prefix[1] = 15 - 1 = 14, one subtraction. Adding the range directly would take 4 additions every time. - Subarrays that add up to k, "k = 7": for
3 4 7 2 -3 1 4 2the dictionary finds 4 stretches in one pass. Try "Negative numbers" (1 -1 1 -1 1withk = 0): there are 6 stretches, and a sliding window could not find them. - Range updates, "Two updates": for
5 5 5 5 5 5, adding 2 to indexes 1 to 3 and subtracting 1 from indexes 2 to 5 changes only 4 slots in the difference array. Looping over the ranges would change 7 items. The final array is5 7 6 6 4 4.
Prefix sum operations
Build the prefix array. Start with prefix = [0]. For each number, append prefix[-1] + number. One pass.
Answer a range query. Return prefix[right + 1] - prefix[left].
Count subarrays that sum to k.
- Start with
total = 0,count = 0and a dictionary{0: 1}. - For each number, add it to
total. - Add the dictionary's count for
total - ktocount. - Add one to the dictionary's count for
total.
Apply range updates with a difference array.
- Make
dwithn + 1zeros. - For each update
(l, r, v), dod[l] += vandd[r + 1] -= v. - Take a running total of
d. Add it to the original array.
Interview fact. Prefix sums trade O(n) memory for turning every range query from O(n) into O(1). The dictionary trick turns an O(n²) "all subarrays" check into O(n).
Prefix sum time complexity
| Operation | Time | Extra memory |
|---|---|---|
| Build the prefix array | O(n) | O(n) |
| One range-sum query | O(1) | O(1) |
Count subarrays that sum to k | O(n) on average | O(n) for the dictionary |
| One range update (difference array) | O(1) | O(1) |
Read the array after u updates | O(n + u) | O(n) |
The dictionary version is O(n) on average because a hash table lookup is O(1) on average. In the unlucky worst case, where many keys land in the same bucket, it can slow down.
Prefix sums vs other approaches
n is the array length and q is the number of queries.
| What you need | Prefix sums | Add the range each time | Sliding window | Fenwick or segment tree |
|---|---|---|---|---|
| Many range sums, data fixed | O(n + q) | O(n times q) | Not applicable | O(n + q log n) |
| Range sums while data changes | O(n) per update | O(n) per query | Not applicable | O(log n) per update and query |
Subarray sum equals k with negatives | O(n), O(n) memory | O(n²) | Does not work | Not needed |
Subarray sum equals k, all positive | O(n), O(n) memory | O(n²) | O(n), O(1) memory | Not needed |
| Many range additions, one final read | O(n + u) (difference array) | O(n times u) | Not applicable | O(n + u log n) |
The bold cells show where each wins. Prefix sums win on fixed data with many queries. They lose as soon as the data changes between queries, and for operations you cannot subtract, such as the maximum.
How to explain prefix sums in an interview
- Say the idea in one line: "I precompute running totals, so any range sum is one subtraction."
- Explain the extra 0 at the front: "it makes the range from index 0 work without a special case".
- For subarray sum equals
k, say why the dictionary starts with{0: 1}and why it works with negatives: "it never assumes the total only grows". - State the trade: O(n) memory for O(1) queries, and name the fix when data changes: a Fenwick or segment tree.
- Mention the 2D version: prefix sums over a grid answer any rectangle sum with four lookups.