AI SWE Prep
0/23in Data Structures & Algorithms
Data Structures & Algorithms

Prefix Sums & Difference Arrays

Precompute once, answer range queries in O(1). The trick behind subarray-sum problems and range updates.

~13 minLesson 17 of 60
Your progressNot started

A prefix sum is a small precomputation that changes the shape of a problem. If you will ask many questions about sums of contiguous ranges, do the addition once up front and turn each later query into subtraction.

Difference arrays are the inverse trick. If many operations add a value across a range, mark only where the range starts and stops, then rebuild the final array with one prefix pass.

Both patterns are the same idea: store cumulative change so repeated range work becomes O(1) per query or update.

The mental model

Build prefix one slot longer than the input. prefix[i] means “sum of the first i elements,” so prefix[0] is 0 and the sum from index left through right is the total before right + 1 minus the total before left.

def build_prefix(nums):
    prefix = [0]
    for x in nums:
        prefix.append(prefix[-1] + x)
    return prefix

def range_sum(prefix, left, right):
    return prefix[right + 1] - prefix[left]

That one extra leading zero removes most boundary bugs.

For range updates, use a difference array:

def apply_updates(n, updates):
    diff = [0] * (n + 1)
    for left, right, delta in updates:
        diff[left] += delta
        diff[right + 1] -= delta

    nums = [0] * n
    running = 0
    for i in range(n):
        running += diff[i]
        nums[i] = running
    return nums

Each update marks “start adding here” and “stop adding after right.” The final prefix pass applies all active deltas.

For a grid, a 2D prefix sum stores the sum of the rectangle from (0, 0) to each cell. A query rectangle uses inclusion-exclusion: big rectangle minus the strip above and the strip left, plus the corner you subtracted twice.

Prefix sums · O(1) range queriesrange [2, 5]
array arr
prefix P · P[k] = P[k-1] + arr[k-1]
00
13
24
38
49
514
623
725
831
sum(arr[2..5]) = P[6] − P[2] = 23 4 = 19direct sum = 19
selected rangePrecompute the prefix array once in O(n); every range-sum query is then a single subtraction — O(1).

Pattern recognition

Variations

Worked problems

All three problems are about refusing to re-add the same range again.

LeetCode 303Easy
  • Prefix sum
  • Range query

Range Sum Query - Immutable

Design a small object that receives an integer list once and then answers many queries asking for the sum between two inclusive indices.

Approach. Store a leading-zero prefix array. Each query subtracts the sum before the left boundary from the sum through the right boundary.

Show solution
class NumArray:
    def __init__(self, nums):
        self.prefix = [0]
        for x in nums:
            self.prefix.append(self.prefix[-1] + x)

    def sumRange(self, left, right):
        return self.prefix[right + 1] - self.prefix[left]

Complexity. O(n) preprocessing time and O(n) space. Each sumRange call is O(1) time.

LeetCode 560Medium
  • Prefix sum
  • Hash map

Subarray Sum Equals K

Given an integer array and a target k, count how many contiguous subarrays sum to exactly k. Values may be negative.

Approach. Let prefix be the sum up to the current index. A subarray ending here has sum k if some earlier prefix was prefix - k. Keep a count of all prefix sums seen so far, starting with {0: 1} so subarrays beginning at index 0 are counted.

Show solution
from collections import defaultdict

def subarray_sum(nums, k):
    seen = defaultdict(int)
    seen[0] = 1

    prefix = 0
    total = 0
    for x in nums:
        prefix += x
        total += seen[prefix - k]
        seen[prefix] += 1

    return total

Complexity. O(n) time, O(n) space. The hash map stores counts of prefix sums, not indices, because multiple starts can lead to the same ending position.

LeetCode 370Medium
  • Difference array
  • Range update

Range Addition

Start with an array of length n filled with zeroes. Each operation gives start, end, and inc, meaning every index in that inclusive range should increase by inc. Return the final array after all operations.

Approach. Mark the beginning and end of each update in a difference array. After all marks are placed, a running sum reconstructs the actual values.

Show solution
def get_modified_array(n, updates):
    diff = [0] * (n + 1)

    for start, end, inc in updates:
        diff[start] += inc
        diff[end + 1] -= inc

    ans = [0] * n
    running = 0
    for i in range(n):
        running += diff[i]
        ans[i] = running

    return ans

Complexity. O(n + u) time and O(n) space, where u is the number of updates. Each range update is recorded in O(1).

When not to use it

Also watch the update/query mix. A plain prefix array is great for immutable data. If the underlying values change between queries, rebuilding the whole prefix array after every update throws away the benefit.

Your progressNot started