Prefix Sum Fundamentals
What is Prefix Sum?
A Prefix Sum array precomputes cumulative sums, allowing O(1) range sum queries after O(n) preprocessing.
Key Formula
For array arr[0..n-1], prefix sum prefix[i] = sum of elements from 0 to i:
prefix[0] = arr[0]
prefix[i] = prefix[i-1] + arr[i] for i > 0
Range sum [l, r] = prefix[r] - (l > 0 ? prefix[l-1] : 0)
Example
arr = [3, 1, 4, 2, 5]
prefix = [3, 4, 8, 10, 15]
Sum [1,3] = prefix[3] - prefix[0] = 10 - 3 = 7 (1+4+2)
Sum [2,4] = prefix[4] - prefix[1] = 15 - 4 = 11 (4+2+5)
Implementation
public class PrefixSum {
private int[] prefix;
private int[] arr;
public PrefixSum(int[] nums) {
arr = nums;
int n = nums.length;
prefix = new int[n];
prefix[0] = nums[0];
for (int i = 1; i < n; i++) {
prefix[i] = prefix[i - 1] + nums[i];
}
}
// Range sum [l, r] inclusive (0-indexed)
public int rangeSum(int l, int r) {
if (l == 0) return prefix[r];
return prefix[r] - prefix[l - 1];
}
// Get prefix sum at index i
public int getPrefixSum(int i) {
return prefix[i];
}
}
2D Prefix Sum
For matrix range sum queries:
public class PrefixSum2D {
private int[][] prefix;
private int m, n;
public PrefixSum2D(int[][] matrix) {
m = matrix.length;
n = matrix[0].length;
prefix = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
prefix[i][j] = matrix[i-1][j-1]
+ prefix[i-1][j] + prefix[i][j-1]
- prefix[i-1][j-1];
}
}
}
// Sum of submatrix from (r1,c1) to (r2,c2) (0-indexed)
public int rangeSum(int r1, int c1, int r2, int c2) {
return prefix[r2+1][c2+1]
- prefix[r1][c2+1]
- prefix[r2+1][c1]
+ prefix[r1][c1];
}
}
Time Complexity
- Build: O(n) for 1D, O(mn) for 2D
- Query: O(1)
- Space: O(n) for 1D, O(mn) for 2D
Advanced Prefix Sum Applications
Prefix Sum + Hash Map
Combining prefix sums with hash maps enables efficient subarray problems.
Subarray Sum Equals K
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> prefixCount = new HashMap<>();
prefixCount.put(0, 1);
int prefixSum = 0;
int count = 0;
for (int num : nums) {
prefixSum += num;
// If (prefixSum - k) exists, we found subarrays summing to k
if (prefixCount.containsKey(prefixSum - k)) {
count += prefixCount.get(prefixSum - k);
}
prefixCount.put(prefixSum, prefixCount.getOrDefault(prefixSum, 0) + 1);
}
return count;
}
Find Pivot Index
public int pivotIndex(int[] nums) {
int totalSum = 0;
for (int num : nums) totalSum += num;
int leftSum = 0;
for (int i = 0; i < nums.length; i++) {
if (leftSum == totalSum - leftSum - nums[i]) {
return i;
}
leftSum += nums[i];
}
return -1;
}
Contiguous Array (Equal 0s and 1s)
public int findMaxLength(int[] nums) {
Map<Integer, Integer> prefixMap = new HashMap<>();
prefixMap.put(0, -1);
int prefixSum = 0;
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
prefixSum += (nums[i] == 1) ? 1 : -1;
if (prefixMap.containsKey(prefixSum)) {
maxLen = Math.max(maxLen, i - prefixMap.get(prefixSum));
} else {
prefixMap.put(prefixSum, i);
}
}
return maxLen;
}
Product of Array Except Self (Prefix Product)
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] result = new int[n];
// Left products
result[0] = 1;
for (int i = 1; i < n; i++) {
result[i] = result[i - 1] * nums[i - 1];
}
// Right products
int rightProduct = 1;
for (int i = n - 1; i >= 0; i--) {
result[i] *= rightProduct;
rightProduct *= nums[i];
}
return result;
}
Practice Problems
Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k.
Example:
Input: nums = [1,1,1], k = 2
Output: 2
[1,1] appears twice as a contiguous subarray.
Solution
```java
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> prefixCount = new HashMap<>();
prefixCount.put(0, 1);
int prefixSum = 0;
int count = 0;
for (int num : nums) {
prefixSum += num;
if (prefixCount.containsKey(prefixSum - k)) {
count += prefixCount.get(prefixSum - k);
}
prefixCount.put(prefixSum, prefixCount.getOrDefault(prefixSum, 0) + 1);
}
return count;
}
```Edge Cases:
- Array contains negative numbers
- k = 0 (count subarrays with sum 0)
- Single element array
- All elements are the same
Quiz
1. What is the time complexity to answer a range sum query using a prefix sum array?
2. Why do we initialize the hash map with {0: 1} in the subarray sum problem?
3. What is the primary purpose of Prefix Sum?
4. What is a common mistake when implementing Prefix Sum?
Flashcards
Question
How do you compute range sum [l, r] using prefix sums?
Click to reveal answer
Answer
rangeSum(l, r) = prefix[r] - (l > 0 ? prefix[l-1] : 0). This gives O(1) range sum queries after O(n) preprocessing.
Question
When should you combine prefix sums with hash maps?
Click to reveal answer
Answer
Use prefix sum + hash map when you need to find subarrays with a specific sum, count subarrays with certain properties, or find subarrays with equal numbers of two types of elements.
Question
What is Prefix Sum?
Click to reveal answer
Answer
Prefix Sum is a key concept in software engineering.
Question
When to use Prefix Sum?
Click to reveal answer
Answer
Use Prefix Sum when building production systems that require reliability, scalability, and maintainability.
Question
Prefix Sum best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Prefix sums enable O(1) range sum queries after O(n) preprocessing
- 2.2D prefix sums work similarly for matrix range queries
- 3.Combining prefix sums with hash maps solves many subarray problems
- 4.Initialize hash map with {0: 1} to handle subarrays starting from index 0
- 5.Prefix products work the same way for multiplicative problems
Interview Tips
- •For range sum queries, always consider prefix sums first
- •Hash map + prefix sum is powerful for finding subarrays with specific sums
- •Remember the formula: sum(l,r) = prefix[r] - prefix[l-1]
- •For 2D problems, use inclusion-exclusion principle with prefix sums
- •Practice: Subarray Sum Equals K, Range Sum Query, Contiguous Array
Cheat Sheet
Prefix Sum Cheat Sheet
1D Prefix Sum
int[] prefix = new int[n];
prefix[0] = arr[0];
for (int i = 1; i < n; i++)
prefix[i] = prefix[i-1] + arr[i];
// Range sum [l, r]
int rangeSum(int l, int r) {
return l == 0 ? prefix[r] : prefix[r] - prefix[l-1];
}
2D Prefix Sum
prefix[i][j] = matrix[i-1][j-1]
+ prefix[i-1][j] + prefix[i][j-1]
- prefix[i-1][j-1];
// Range sum (r1,c1) to (r2,c2)
return prefix[r2+1][c2+1] - prefix[r1][c2+1]
- prefix[r2+1][c1] + prefix[r1][c1];
Prefix Sum + Hash Map
Map<Integer, Integer> prefixCount = new HashMap<>();
prefixCount.put(0, 1);
int prefixSum = 0, count = 0;
for (int num : nums) {
prefixSum += num;
if (prefixCount.containsKey(prefixSum - k))
count += prefixCount.get(prefixSum - k);
prefixCount.merge(prefixSum, 1, Integer::sum);
}
Applications
- Range Sum Queries: O(1) after O(n) build
- Subarray Sum Equals K
- Contiguous Array (equal 0s and 1s)
- Pivot Index
- Product of Array Except Self