Prefix Sum: Range Query Code Templates in 6 Languages
If you have not read the concept guide yet, start there for the intuition and the complexity analysis. This page gives you the code you can memorize and adapt in an interview. Every template below builds in
Main Template: Prefix Sum Array
The core version precomputes a running total so any subarray sum is a single subtraction. This is the class behind Range Sum Query - Immutable, and it works whenever the input array does not change between queries.
Use this for Range Sum Query - Immutable and as the foundation for every other variation.
class PrefixSum {
constructor(nums) {
// prefix[i] holds the sum of the first i elements.
// The leading 0 lets a query starting at index 0
// subtract a real value instead of needing a branch.
this.prefix = new Array(nums.length + 1).fill(0);
for (let i = 0; i < nums.length; i++) {
this.prefix[i + 1] = this.prefix[i] + nums[i];
}
}
rangeSum(left, right) {
// Everything up to and including right, minus
// everything before left, isolates nums[left..right].
return this.prefix[right + 1] - this.prefix[left];
}
}Code Breakdown
Key Variables
prefix: the precomputed array, always one element longer thannums. Entryprefix[i]holds the sum of the firstiinput elements. That single convention drives every other line.nums.length + 1(or equivalent): the size of the prefix array. The extra slot holds the empty-prefix sum of 0 and keepsprefix[right + 1]in bounds whenrightis the last index.
Visual Mechanism
graph TD
A["Input: nums = [3, 1, 4, 2, 5]"] --> B["prefix[0] = 0"]
B --> C["prefix[1] = prefix[0] + 3 = 3"]
C --> D["prefix[2] = prefix[1] + 1 = 4"]
D --> E["prefix[3] = prefix[2] + 4 = 8"]
E --> F["prefix[4] = prefix[3] + 2 = 10"]
F --> G["prefix[5] = prefix[4] + 5 = 15"]
G --> H["rangeSum(2, 4) = prefix[5] - prefix[2] = 15 - 4 = 11"]
Critical Sections
The build loop reads one element per step and writes the running total one slot ahead. prefix[i] always stores the total of nums[0..i-1], so the first element lands at index 1 and index 0 stays as the neutral 0. If you size the array as n + 1, you never have to special-case a query that starts at index 0.
The query is a single subtraction because prefix[right + 1] includes everything through right, and subtracting prefix[left] removes everything before left. The length of the range never appears in the formula, which is why the query cost does not depend on the range size.
Variations
1. In-place running sum
When the task only wants the transformed array (like LeetCode 1480 Running Sum) and never asks for a subarray query afterward, you can overwrite nums and save the extra
function runningSum(nums) {
for (let i = 1; i < nums.length; i++) {
nums[i] += nums[i - 1];
}
return nums;
}This trades memory for a loss of flexibility. Once you overwrite nums[i], the original value is gone, so you can no longer answer arbitrary range queries. Use it only when the problem is satisfied with the transformed array itself.
2. Hashmap counting (subarray sum equals k)
When the question is “how many subarrays sum to K”, no single prefix entry answers it. You store every prefix sum you have seen in a hashmap keyed by value, and for each new prefix you ask how many earlier prefixes equal prefix - K. The 0: 1 seed counts subarrays that start at index 0.
Use this for Subarray Sum Equals K .
function subarraySum(nums, k) {
const seen = new Map();
seen.set(0, 1); // empty prefix counts once
let total = 0;
let result = 0;
for (const num of nums) {
total += num;
// An earlier prefix of total - k means the subarray
// between that prefix and here sums to exactly k.
result += seen.get(total - k) || 0;
seen.set(total, (seen.get(total) || 0) + 1);
}
return result;
}Time is
3. 2D prefix array (grids)
The same idea extends to matrices. A prefix cell at (i+1, j+1) stores the sum of the whole submatrix from (0,0) to (i,j). A submatrix query is then inclusion-exclusion over four corners: take the big rectangle, subtract the strip above, subtract the strip to the left, and add back the corner region that was subtracted twice.
Use this for Range Sum Query 2D - Immutable .
class NumMatrix:
def __init__(self, matrix: list[list[int]]):
h, w = len(matrix), len(matrix[0])
# prefix has one extra row and column so the top-left
# corner of any query stays inside the array.
self.prefix = [[0] * (w + 1) for _ in range(h + 1)]
for i in range(h):
for j in range(w):
self.prefix[i+1][j+1] = (matrix[i][j]
+ self.prefix[i][j+1]
+ self.prefix[i+1][j]
- self.prefix[i][j])
def sum_region(self, r1, c1, r2, c2):
# Big rectangle minus the above strip and the left
# strip, then re-add the corner removed twice.
return (self.prefix[r2+1][c2+1]
- self.prefix[r1][c2+1]
- self.prefix[r2+1][c1]
+ self.prefix[r1][c1])Build cost is
4. Difference array (range updates)
When the problem applies many “+val to interval [L, R]” operations and you only read the final array, record +val at L and -val at R+1, then one prefix pass materializes the result. This is the update-side mirror of the prefix sum.
Use this for Corporate Flight Bookings .
function differenceArray(n, updates) {
const diff = new Array(n + 1).fill(0);
for (const [left, right, val] of updates) {
diff[left] += val;
diff[right + 1] -= val; // cancel the addition one past the end
}
const result = new Array(n);
let run = 0;
for (let i = 0; i < n; i++) {
run += diff[i]; // prefix pass turns deltas into values
result[i] = run;
}
return result;
}Each update is
Now head to the practice problems to apply these templates to real challenges.