Card 03/ 08
The Prefix Sum Template in Python, Java and TypeScript
Build the n + 1 totals in one loop, then answer each range with p[j + 1] − p[i].
The prefix sum template is one loop that builds n + 1 running totals and one function that reads a range from two of them. Two lines change between problems, and the highlighted lines mark them: the value accumulated, which can be a count or a flag instead of a number, and the read. Each listing builds the prefix array of 2 6 1 4 3, reads three ranges, and adds three readings of 2,000,000,000.
The prefix sum template in three languages
def build_prefix(values: list[int]) -> list[int]:
prefix = [0] * (len(values) + 1)
for i, value in enumerate(values):
prefix[i + 1] = prefix[i] + value
return prefix
def range_sum(prefix: list[int], i: int, j: int) -> int:
return prefix[j + 1] - prefix[i]
values = [2, 6, 1, 4, 3]
prefix = build_prefix(values)
print(f"values {values} prefix {prefix}")
for i, j in [(1, 3), (0, 4), (2, 2)]:
print(f"sum of indices {i} to {j}: {range_sum(prefix, i, j)}")
large = build_prefix([2_000_000_000] * 3)
print(f"three readings of 2000000000: total {range_sum(large, 0, 2)}")values [2, 6, 1, 4, 3] prefix [0, 2, 8, 9, 13, 16]
sum of indices 1 to 3: 11
sum of indices 0 to 4: 16
sum of indices 2 to 2: 1
three readings of 2000000000: total 6000000000import java.util.Arrays;
public class PrefixSum {
static long[] buildPrefix(int[] values) {
long[] prefix = new long[values.length + 1];
for (int i = 0; i < values.length; i++) {
prefix[i + 1] = prefix[i] + values[i];
}
return prefix;
}
static long rangeSum(long[] prefix, int i, int j) {
return prefix[j + 1] - prefix[i];
}
public static void main(String[] args) {
int[] values = {2, 6, 1, 4, 3};
long[] prefix = buildPrefix(values);
System.out.println("values " + Arrays.toString(values) + " prefix " + Arrays.toString(prefix));
int[][] ranges = {{1, 3}, {0, 4}, {2, 2}};
for (int[] range : ranges) {
System.out.println("sum of indices " + range[0] + " to " + range[1] + ": " + rangeSum(prefix, range[0], range[1]));
}
long[] large = buildPrefix(new int[] {2_000_000_000, 2_000_000_000, 2_000_000_000});
System.out.println("three readings of 2000000000: total " + rangeSum(large, 0, 2));
}
}values [2, 6, 1, 4, 3] prefix [0, 2, 8, 9, 13, 16]
sum of indices 1 to 3: 11
sum of indices 0 to 4: 16
sum of indices 2 to 2: 1
three readings of 2000000000: total 6000000000function buildPrefix(values: number[]): number[] {
const prefix: number[] = new Array(values.length + 1).fill(0);
for (let i = 0; i < values.length; i++) {
prefix[i + 1] = prefix[i] + values[i];
}
return prefix;
}
function rangeSum(prefix: number[], i: number, j: number): number {
return prefix[j + 1] - prefix[i];
}
const values = [2, 6, 1, 4, 3];
const prefix = buildPrefix(values);
console.log(`values [${values.join(", ")}] prefix [${prefix.join(", ")}]`);
for (const [i, j] of [[1, 3], [0, 4], [2, 2]]) {
console.log(`sum of indices ${i} to ${j}: ${rangeSum(prefix, i, j)}`);
}
const large = buildPrefix([2_000_000_000, 2_000_000_000, 2_000_000_000]);
console.log(`three readings of 2000000000: total ${rangeSum(large, 0, 2)}`);values [2, 6, 1, 4, 3] prefix [0, 2, 8, 9, 13, 16]
sum of indices 1 to 3: 11
sum of indices 0 to 4: 16
sum of indices 2 to 2: 1
three readings of 2000000000: total 6000000000The three listings print the same totals. Building is O(n) time and O(n) extra space for n values, and each read is O(1).
The large total is where the languages part. A Java int holds at most 2³¹ − 1, about 2.1 × 10⁹, so the Java listing stores the totals as long; with int[], a total past that limit wraps round to a negative number with no error. A TypeScript number holds every integer exactly up to 2⁵³, about 9 × 10¹⁵, and rounds beyond it. Python's integers have no limit.
← → move through sections and cards