Table of Contents
789 words
4 minutes
Prefix Sums: Reducing Range Sum Queries from O(n) to O(1)

Overview#

Prefix Sum is a preprocessing technique: first store the cumulative value from the beginning to the current position, then the sum of any contiguous interval can be obtained by subtracting the results of two queries.

Prerequisites

  • Array indexing: The prefix array usually has one extra slot to reduce boundary-handling overhead
  • Interval representation: Clearly distinguish the difference between [l, r] and [l, r)
  • Hash map: Used to count prefix sum occurrences, solving “subarrays with sum K”

Problem Definition#

Given an array and multiple interval queries, quickly compute the sum or related cumulative value of any contiguous interval.

ElementDescription
InputOriginal array, interval endpoints, target sum
OutputInterval sum, number of qualifying subarrays, or derived cumulative value
Preprocessingprefix[i + 1] = prefix[i] + nums[i]
Query formulasum(l, r) = prefix[r + 1] - prefix[l]

Core Principle: Step-by-Step Illustration#

Using the array [1, 3, 5, 2, 4] as an example:

nums: 1 3 5 2 4
index: 0 1 2 3 4
prefix: 0 1 4 9 11 15

Querying the interval nums[1..3]:

prefix[4] - prefix[1] = 11 - 1 = 10
nums[1] + nums[2] + nums[3] = 3 + 5 + 2 = 10
Original array Build prefix Cumulative up to interval right end Cumulative before interval left end Subtract to get interval sum

The advantage of having one extra slot prefix[0] = 0 is that intervals starting from index 0 can also use the same formula.


Detailed Algorithm Steps#

Algorithm: PrefixSum(nums)
Input: array nums
Output: prefix array that allows O(1) range sum queries
1. Create an array prefix of length nums.length + 1, initialized to 0
2. for i from 0 to nums.length - 1:
3. prefix[i + 1] ← prefix[i] + nums[i]
4. When querying [l, r], return prefix[r + 1] - prefix[l]

Complexity analysis:

OperationTime complexitySpace complexityDescription
Build prefix sumO(n)O(n)One linear scan
Single interval queryO(1)O(1)Subtract two prefix values
m interval queriesO(n + m)O(n)Preprocess first, then query
Subarray sum equals KO(n)O(n)Prefix sum + hash counting

TypeScript Implementation#

1. Basic Prefix Sum#

function buildPrefixSum(nums: number[]): number[] {
const prefix = new Array(nums.length + 1).fill(0);
for (let i = 0; i < nums.length; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
return prefix;
}
function rangeSum(prefix: number[], left: number, right: number): number {
return prefix[right + 1] - prefix[left];
}

2. Range Sum Query#

class NumArray {
private prefix: number[];
constructor(nums: number[]) {
this.prefix = buildPrefixSum(nums);
}
sumRange(left: number, right: number): number {
return this.prefix[right + 1] - this.prefix[left];
}
}

3. Subarrays with Sum K#

function subarraySum(nums: number[], k: number): number {
const countByPrefix = new Map<number, number>();
countByPrefix.set(0, 1);
let prefix = 0;
let count = 0;
for (const num of nums) {
prefix += num;
count += countByPrefix.get(prefix - k) ?? 0;
countByPrefix.set(prefix, (countByPrefix.get(prefix) ?? 0) + 1);
}
return count;
}

4. Maximum Subarray Sum from a Prefix Perspective#

function maxSubArray(nums: number[]): number {
let prefix = 0;
let minPrefix = 0;
let best = nums[0];
for (const num of nums) {
prefix += num;
best = Math.max(best, prefix - minPrefix);
minPrefix = Math.min(minPrefix, prefix);
}
return best;
}

5. Prefix Product Variant#

function productExceptSelf(nums: number[]): number[] {
const result = new Array(nums.length).fill(1);
let leftProduct = 1;
for (let i = 0; i < nums.length; i++) {
result[i] = leftProduct;
leftProduct *= nums[i];
}
let rightProduct = 1;
for (let i = nums.length - 1; i >= 0; i--) {
result[i] *= rightProduct;
rightProduct *= nums[i];
}
return result;
}

Engineering Optimization: Unifying Interval Semantics#

The most common bugs in prefix sums come from endpoint confusion. It is recommended to consistently use the pattern of “prefix array with one extra slot + querying the closed interval [left, right]”.

ScenarioRecommended expressionReason
1D interval sumprefix[right + 1] - prefix[left]Covers intervals starting from 0
Subarray countingprefix - kConverts interval sums into historical prefix queries
2D prefix sumAdd one extra row and columnAvoids special-casing the top and left boundaries
Frequent updatesNot suitable for ordinary prefix sumsConsider a Fenwick tree or segment tree instead

If the array is modified frequently, ordinary prefix sums require rebuilding after every update, so you should switch to a data structure that supports dynamic updates.


Applications and Limitations#

Typical Applications#

  • Multiple static interval sum queries
  • Subarrays with sum K, contiguous interval counting
  • 2D matrix region sum
  • Variants such as prefix XOR, prefix product, prefix extrema, etc.

Limitations#

LimitationDescription
Not suitable for frequent point updatesUpdating one value affects all subsequent prefixes
Only suitable for invertible or accumulable operationsInterval sums can be subtracted, but maximum values cannot be directly subtracted
Requires extra spaceGenerally requires an O(n) preprocessing array

Summary#

Original array Build prefix array Cumulative value at right end Cumulative value before left end Interval result

Key points:

  1. Prefix sum = preprocessing cumulative values + O(1) interval queries.
  2. Having one extra slot prefix[0] = 0 unifies the boundary formula.
  3. Prefix sum + hash map is the core model for “subarrays with sum K”.
  4. Use prefix sums for static queries; consider a Fenwick tree or segment tree for dynamic updates.
Prefix Sums: Reducing Range Sum Queries from O(n) to O(1)
https://www.hehonglei.com/technology/prefix-sum/
Author
HHLBlog
Published at
2026-04-26
License
CC BY-NC-SA 4.0