Prefix Sum 101
Fundamental · 4 chapters · 8 min read · Precompute running totals once and answer any range-sum question instantly.
Practise this in the app All guides
What prefix sums are
The idea
A prefix sum array stores, at position i, the total of all elements before it. With pre[0] = 0 and pre[i + 1] = pre[i] + a[i], the sum of any range a[l..r] is simply pre[r + 1] - pre[l]. You pay O(n) once to build it and then answer each range-sum query in O(1).
The deeper insight is that a subarray sum is the difference of two prefix sums. That turns questions about subarrays into questions about pairs of prefix values, and pairs can be found quickly with a hash map. This is what makes prefix sums powerful in interviews, far beyond simple range queries.
Signals in a problem statement
- "Sum of elements between index
iandj", asked many times. - "Count subarrays whose sum equals
k", especially when numbers can be negative (sliding window fails there). - "Pivot" or "balance" index where the left sum equals the right sum.
- "Longest subarray with equal numbers of 0s and 1s" — replace 0 with -1 and look for sum 0.
- "Subarray sum divisible by
k" — look at prefix sums modulok. - 2D grids: "sum of a sub-rectangle".
Mental model
Picture a running balance in a bank passbook. The amount spent between two dates is the balance on the first date minus the balance on the second. You never need to add up the individual transactions again. Similarly, if two moments have the same balance, nothing net was added between them: that is exactly the "subarray with sum 0" condition.
Core patterns with templates
1. Build and query
def build_prefix(a):
pre = [0] * (len(a) + 1)
for i, x in enumerate(a):
pre[i + 1] = pre[i] + x
return pre
def range_sum(pre, l, r):
return pre[r + 1] - pre[l]
Python's itertools.accumulate(a, initial=0) builds the same list in one line.
2. Pivot index (left sum equals right sum)
def pivot_index(a):
total, left = sum(a), 0
for i, x in enumerate(a):
if left == total - left - x:
return i
left += x
return -1
3. Count subarrays with sum k (prefix sum + hash map)
from collections import defaultdict
def subarray_sum(a, k):
count = defaultdict(int)
count[0] = 1
run = ans = 0
for x in a:
run += x
ans += count[run - k]
count[run] += 1
return ans
Seeding count[0] = 1 handles subarrays that start at index 0. Example: a = [1, 2, 3], k = 3. Running sums are 1, 3, 6. At 3 we find count[0] = 1 (subarray [1,2]); at 6 we find count[3] = 1 (subarray [3]). Answer 2.
4. Longest subarray with sum 0 (first occurrence)
def longest_balanced(bits):
first = {0: -1}
run = best = 0
for i, b in enumerate(bits):
run += 1 if b == 1 else -1
if run in first:
best = max(best, i - first[run])
else:
first[run] = i
return best
For counting store how many times each sum appeared; for longest store the first index only.
Complexity, mistakes and edge cases
Complexity
| Task | Time | Space |
|---|---|---|
| Build prefix array | O(n) | O(n) |
| One range query | O(1) | |
| Count subarrays with sum k | O(n) | O(n) map |
| 2D prefix build | O(rows × cols) | O(rows × cols) |
Common mistakes
- Off-by-one in the prefix array. Using
pre[i] = a[0] + ... + a[i](inclusive) makes the range formulapre[r] - pre[l - 1], which breaks atl = 0. The extra leading zero avoids this. - Forgetting
count[0] = 1orfirst = {0: -1}, so subarrays that start at the beginning are missed. - Updating the map before querying. In the counting template, look up
run - kfirst, then recordrun; otherwisek = 0counts empty subarrays. - Reaching for sliding window with negative numbers. If values can be negative, the window is not monotonic; prefix sums with a map are the right tool.
- Overwriting the first index in "longest" problems. Only store an index the first time a sum appears.
- Modulo with negatives. In Python
-1 % 5is 4, which is what you want; in Java or C++ you must addkand take the modulo again.
Edge cases
Empty array, single element, all zeros (many overlapping answers), k = 0, very large or very negative values, and a pivot at index 0 or at the last index (the empty side sums to 0).
2D prefix sums in one formula
P[i+1][j+1] = grid[i][j] + P[i][j+1] + P[i+1][j] - P[i][j]. The sum of the rectangle from (r1, c1) to (r2, c2) is P[r2+1][c2+1] - P[r1][c2+1] - P[r2+1][c1] + P[r1][c1]. Draw the four rectangles once and you will never forget it.
Variations and practise
How interviewers twist it
- Transform the input first. Replace 0 with -1 to turn "equal zeros and ones" into "sum zero". Replace each element with
1 if odd else 0to count subarrays with exactlykodd numbers. - Divisible by k. Two prefix sums with the same remainder modulo
kbound a subarray whose sum is divisible byk. - Product instead of sum. "Product of array except self" uses a prefix product from the left and a suffix product from the right, without division.
- Difference arrays. The reverse idea: to add
vto every element in[l, r]many times, addvatland subtract it atr + 1, then take one prefix sum at the end. Great for booking and range-update questions. - Updates between queries. If the array changes, a plain prefix array costs O(n) per update. Mention a Fenwick tree or segment tree for O(log n) updates and queries, even if you do not code it.
How to explain it
Say: "A subarray sum is pre[j] - pre[i], so I need the number of earlier prefix values equal to pre[j] - k, which I keep in a hash map." That one sentence shows you understand the idea rather than a memorised template.
Practise
The problems below cover the pivot index, counting subarrays with a target sum (with negatives allowed), and the longest balanced subarray. For each one, write the first few running sums on paper before coding.
Practise
Easy
- 979. Find the Highest Altitude
- 980. Find Pivot Index
- 985. First Overdraft Day
- 990. Ledger Running Balances
- 991. Bookshelf Weight Queries
- 992. Minimum Opening Stamina
- 993. Left-Right Weight Gap
- 994. Front-Heavy Cut Count
- 995. Even Total Range Checks
- 996. Vowel Bookend Word Ranges
- 997. Running Floor Average
- 998. Two-Way Equal Cut
- 999. Longest Non-Negative Opening
- 1000. Lit Bulbs in Ranges
- 1001. Best Split of a Vote String
- 1002. Odd-Length Window Total
- 1003. Bulk Range Increments
- 1004. Busiest Year of the Colony
- 1005. Shortest Prefix to Target
- 1006. Range XOR Lookups
- 1007. Unscramble a Prefix XOR
- 1008. Deepest Bracket Level
- 1009. Covered Mile Markers
- 1010. Lead Change Count
- 1011. Matches the Prior Average
- 1012. Best K-Day Stretch
- 1013. Synchronized Runners
- 1014. Grid Row Running Totals
- 1015. Balanced Letter Prefixes
- 1016. Alternating-Sign Range Sum
- 1017. Dips Below Sea Level
- 1018. Letter Count in Ranges
- 1019. New Record Totals
- 1020. Prefix Divisible Count
- 1021. Three Equal Segments
- 1022. Range Product Sign
- 1023. Page of a Character
Medium
- 981. Subarray Sum Equals K
- 982. Contiguous Array
- 986. Rectangle Sum Lookups
- 987. Divisible Total Subarrays
- 988. Multiple-of-K Run
- 1024. Longest Exact-Total Stretch
- 1025. Cafe Closing Hour
- 1026. Shift Letters by Ranges
- 1027. Gather Coins Into Each Box
- 1028. Meeting Point Cost Queries
- 1029. Exactly K Odd Stretches
- 1030. Longest Productive Period
- 1031. Trim to a Divisible Total
- 1032. Peel Ends to Exact Zero
- 1033. Two Disjoint Windows
- 1034. Ordered Three-Part Splits
- 1035. Value Count in Ranges
- 1036. Lanterns Between Posts
- 1037. Equal XOR Triplets
- 1038. Near-Palindrome Substrings
- 1039. Rearrange-to-Palindrome Queries
- 1040. Downward Path Totals
- 1041. Erase Zero-Sum Runs
- 1042. Neighborhood Block Totals
- 1043. Largest Square Under Budget
- 1044. Top-Left Anchored Regions
- 1045. Balanced Marker Regions
- 1046. Grid Patch Increments
- 1047. Steadiest Split Index
- 1048. Cards From Both Ends
- 1049. More Ones Than Zeros Runs
- 1050. Odd Sum Subarray Count
- 1051. Fair After One Removal
- 1052. Length-Multiple Best Sum
- 1053. Bookend Gap Subarray
- 1054. Modular Hit Subarrays
- 1055. Mirrored Pair Target
- 1056. Calm Days to Launch
- 1057. Flips to Sorted Switches
- 1058. Cluster Ones on a Ring
- 1059. Cheapest Valley Triplet
- 1060. Ordered Drop and Scale
- 1061. Min Times Total Best
- 1062. Alternating Building Picks
- 1063. Two-Robot Corridor
- 1064. Live Range Sum Ledger
- 1065. Largest Swing Subarray
- 1066. Age-Gap Invitations
- 1067. Sorted Window Sum Range
- 1068. Chalk Round Robin
- 1069. Weighted Window Scores
- 1070. Staircase Range Adds
- 1071. Alternating Parity Queries
- 1072. Best Arrangement for Requests
- 1073. Three Even Ones Splits
- 1074. Repeated Strip Best Sum
- 1075. Scenic Pair Score
- 1076. Bounded Jump Reachability
- 1077. Card Draw Odds
- 1078. Most Disjoint Target Runs
- 1079. Two Target Runs, Min Length
- 1080. Raise to Match Frequency
- 1081. Radius Averages
- 1082. Good Cut Distinct Letters
- 1083. Bounded-Length Best Window
- 1084. Three-Letter Balance
- 1085. Best Carpet Placement
- 1086. Level Out with Range Steps
- 1087. Removal Rounds Score Gap
- 1088. Best Group Averages
- 1111. Sum of Squared Window Totals
- 1112. Bounded Ring Window
- 1115. Largest Well-Covered Roof Square
- 1117. Kth Largest Region XOR
Hard
- 983. Number of Submatrices That Sum to Target
- 984. Count of Range Sum
- 989. Shortest Run Reaching K
- 1089. Median-Anchored Subarrays
- 1090. Rectangle Sum Under Cap
- 1091. Merge Piles K at a Time
- 1092. Finishing Orders with K Upsets
- 1093. Total Squad Power
- 1094. Floored Ratio Sum
- 1095. Best Average Long Window
- 1096. Pack K Ones Together
- 1097. Weighted Equalize Cost
- 1098. Trim Then Compare Halves
- 1099. Largest Balanced Binary Block
- 1100. Five-Length Mirror Subsequences
- 1101. Stamp Cover Check
- 1102. Rising Quadruplets
- 1103. Live Grid Region Sums
- 1104. Cake Cuts with Cherries
- 1105. Place Mailboxes
- 1106. Range At-Most Counts
- 1107. Flip K Switches to On
- 1108. Longest Mergeable Ascent
- 1109. Prime-Start Partitions
- 1110. Spaced Suffix Sum Queries
- 1113. Longest Above-Average Run
- 1114. Port Delivery Trips
- 1116. Repeated Strip Zero Runs
- 1118. Even Loads by Neighbour Passing
- 1119. Range Sum Runs with Length Cap
- 1120. Balanced Split into K Equal Parts
- 1121. Max Gain from One Range Swap