You're in an interview. The problem is Range Sum Query. You know the pattern. You write:
def __init__(self, nums):
self.prefix = []
for num in nums:
if self.prefix:
self.prefix.append(self.prefix[-1] + num)
else:
self.prefix.append(num)
def sumRange(self, left, right):
if left == 0:
return self.prefix[right]
return self.prefix[right] - self.prefix[left - 1]You submit. Wrong Answer.
The test case sumRange(0, 2) on array [1, 2, 3] should return 6, but your code returns 3.
What went wrong? Off-by-one errors in prefix sum are the most common mistake beginners make. They're subtle, frustrating, and cost interviews.
In this guide, you'll learn why off-by-one errors happen, the prefix[0] = 0 trick that prevents them, and the correct formula that works every time.
TL;DR
- Always start with
prefix = [0]to avoid special cases - Use the formula:
sum(i, j) = prefix[j+1] - prefix[i] - Prefix array size:
len(nums) + 1(one extra element) - Why it works: The padding eliminates edge cases and makes the formula consistent
The Most Common Mistake
Example of Wrong Answer
# WRONG APPROACH
class NumArray:
def __init__(self, nums):
self.prefix = []
for num in nums:
if self.prefix:
self.prefix.append(self.prefix[-1] + num)
else:
self.prefix.append(num)
def sumRange(self, left, right):
if left == 0:
return self.prefix[right]
return self.prefix[right] - self.prefix[left - 1]
# Test
nums = [1, 2, 3, 4, 5]
obj = NumArray(nums)
print(obj.sumRange(0, 2)) # Expected: 6, Got: 3 ❌
print(obj.sumRange(1, 3)) # Expected: 9, Got: 9 ✓Why It Happens
The bug: When left = 0, we use prefix[right] directly. But our prefix array is:
nums: [1, 2, 3, 4, 5]
prefix: [1, 3, 6, 10, 15]
↑
This is nums[0], not sum(0, 0)!So sumRange(0, 2) returns prefix[2] = 6, which is correct by accident. But wait, let me trace again:
Actually, the issue is more subtle. Let me trace carefully:
sumRange(0, 2):
left = 0, so return prefix[2] = 6 ✓ (works by accident)
sumRange(1, 3):
left = 1, so return prefix[3] - prefix[0] = 10 - 1 = 9 ✓ (works)Wait, this actually works? Let me find the real bug...
The real bug appears when you try to handle ranges differently:
# Another wrong approach
def sumRange(self, left, right):
return self.prefix[right] - self.prefix[left] # Missing +1 on right!
# Test
nums = [1, 2, 3, 4, 5]
prefix = [1, 3, 6, 10, 15]
sumRange(1, 3) = prefix[3] - prefix[1] = 10 - 3 = 7
# Expected: 2 + 3 + 4 = 9 ❌The root cause: inconsistent indexing between the original array and the prefix array.
The prefix[0] = 0 Trick
Why We Need It
Starting the prefix array with 0 solves all these problems:
# CORRECT APPROACH
class NumArray:
def __init__(self, nums):
self.prefix = [0] # Start with 0!
for num in nums:
self.prefix.append(self.prefix[-1] + num)
def sumRange(self, left, right):
# One formula for all cases
return self.prefix[right + 1] - self.prefix[left]
# Test
nums = [1, 2, 3, 4, 5]
obj = NumArray(nums)
print(obj.sumRange(0, 2)) # 6 ✓
print(obj.sumRange(1, 3)) # 9 ✓
print(obj.sumRange(2, 2)) # 3 ✓Visual Example
With padding (correct):
nums: [1, 2, 3, 4, 5]
index: 0 1 2 3 4
prefix: [0, 1, 3, 6, 10, 15]
index: 0 1 2 3 4 5
↑
Padding with 0
sum(1, 3) = prefix[4] - prefix[1] = 10 - 1 = 9
Verify: 2 + 3 + 4 = 9 ✓
sum(0, 2) = prefix[3] - prefix[0] = 6 - 0 = 6
Verify: 1 + 2 + 3 = 6 ✓
sum(2, 2) = prefix[3] - prefix[2] = 6 - 3 = 3
Verify: 3 = 3 ✓Without padding (buggy):
nums: [1, 2, 3, 4, 5]
index: 0 1 2 3 4
prefix: [1, 3, 6, 10, 15]
index: 0 1 2 3 4
sum(1, 3) = prefix[3] - prefix[0] = 10 - 1 = 9 ✓ (works)
sum(0, 2) = ???
- Can't use prefix[2] - prefix[-1] (out of bounds)
- Must special case: return prefix[2] = 6
- Inconsistent formula!Code Comparison
Without padding (requires special case):
def sumRange(self, left, right):
if left == 0:
return self.prefix[right] # Special case
return self.prefix[right] - self.prefix[left - 1]With padding (one formula for all):
def sumRange(self, left, right):
return self.prefix[right + 1] - self.prefix[left] # Always worksThe Correct Range Formula
Why sum(i, j) = prefix[j+1] - prefix[i]?
Mathematical proof:
prefix[i] = sum of elements from index 0 to i-1prefix[j+1] = sum of elements from index 0 to j
Therefore:
prefix[j+1] - prefix[i]
= (nums[0] + ... + nums[j]) - (nums[0] + ... + nums[i-1])
= nums[i] + nums[i+1] + ... + nums[j]
= sum(i, j)Visual Proof
Array: [3, 1, 4, 1, 5, 9]
Index: 0 1 2 3 4 5
Prefix: [0, 3, 4, 8, 9, 14, 23]
Index: 0 1 2 3 4 5 6
Query: sum(2, 4) = sum of elements at indices 2, 3, 4
prefix[5] = 0 + 3 + 1 + 4 + 1 + 5 = 14
prefix[2] = 0 + 3 + 1 = 4
prefix[5] - prefix[2] = 14 - 4 = 10
Verify: 4 + 1 + 5 = 10 ✓
Formula: sum(2, 4) = prefix[4+1] - prefix[2] = prefix[5] - prefix[2]Common Formula Mistakes
❌ Wrong: prefix[right] - prefix[left]
- This gives sum(left+1, right), missing the element at
left
❌ Wrong: prefix[right] - prefix[left - 1]
- Crashes when
left = 0(index -1) - Requires special case handling
❌ Wrong: prefix[right + 1] - prefix[left + 1]
- This gives sum(left+1, right), missing the element at
left
✅ Correct: prefix[right + 1] - prefix[left]
- Works for all cases, including
left = 0 - No special cases needed
Mistake 1: Wrong Range Calculation
The Bug
# WRONG
def sumRange(self, left, right):
return self.prefix[right] - self.prefix[left]Example That Fails
nums = [1, 2, 3, 4, 5]
prefix = [0, 1, 3, 6, 10, 15]
sumRange(1, 3) = prefix[3] - prefix[1] = 6 - 1 = 5
Expected: 2 + 3 + 4 = 9 ❌
Got: 5 (which is 2 + 3, missing the 4)Why It Happens
prefix[right] gives the sum from 0 to right-1, not 0 to right.
The Fix
# CORRECT
def sumRange(self, left, right):
return self.prefix[right + 1] - self.prefix[left]Mistake 2: Not Padding the Array
The Bug
# WRONG
self.prefix = []
for num in nums:
if self.prefix:
self.prefix.append(self.prefix[-1] + num)
else:
self.prefix.append(num)Why It's Wrong
- Inconsistent formula: Need special case for
left = 0 - Prone to errors: Easy to forget the special case
- Harder to debug: Different code paths for different inputs
The Fix
# CORRECT
self.prefix = [0] # Always start with 0
for num in nums:
self.prefix.append(self.prefix[-1] + num)Mistake 3: Confusing Inclusive/Exclusive Bounds
The Confusion
In programming, we often use exclusive right bounds (like range(0, 5) goes from 0 to 4).
But in prefix sum problems, the range is usually inclusive on both ends.
Example
Problem: "Calculate sum from index left to right inclusive"
nums = [1, 2, 3, 4, 5]
sumRange(1, 3) should include indices 1, 2, 3
= nums[1] + nums[2] + nums[3]
= 2 + 3 + 4
= 9The Formula
For inclusive range [left, right]:
sum_range = prefix[right + 1] - prefix[left]The +1 on right accounts for the inclusive bound.
How to Remember
Think of it this way:
prefix[i]= sum of firstielements (indices 0 to i-1)- To include element at index
right, we needprefix[right + 1]
The Correct Template
Python
class NumArray:
def __init__(self, nums: List[int]):
# Build prefix sum with padding
self.prefix = [0]
for num in nums:
self.prefix.append(self.prefix[-1] + num)
def sumRange(self, left: int, right: int) -> int:
# Inclusive range [left, right]
return self.prefix[right + 1] - self.prefix[left]JavaScript
class NumArray {
constructor(nums) {
this.prefix = [0];
for (const num of nums) {
this.prefix.push(this.prefix[this.prefix.length - 1] + num);
}
}
sumRange(left, right) {
return this.prefix[right + 1] - this.prefix[left];
}
}Java
class NumArray {
private int[] prefix;
public NumArray(int[] nums) {
prefix = new int[nums.length + 1]; // Size is n+1
for (int i = 0; i < nums.length; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
}
public int sumRange(int left, int right) {
return prefix[right + 1] - prefix[left];
}
}Testing Your Implementation
Test Cases to Verify
# Test 1: Range from start
nums = [1, 2, 3, 4, 5]
obj = NumArray(nums)
assert obj.sumRange(0, 2) == 6 # 1 + 2 + 3
# Test 2: Range in middle
assert obj.sumRange(1, 3) == 9 # 2 + 3 + 4
# Test 3: Single element
assert obj.sumRange(2, 2) == 3 # 3
# Test 4: Entire array
assert obj.sumRange(0, 4) == 15 # 1 + 2 + 3 + 4 + 5
# Test 5: Range at end
assert obj.sumRange(3, 4) == 9 # 4 + 5
# Test 6: Negative numbers
nums2 = [-2, 0, 3, -5, 2, -1]
obj2 = NumArray(nums2)
assert obj2.sumRange(0, 2) == 1 # -2 + 0 + 3
assert obj2.sumRange(2, 5) == -1 # 3 + (-5) + 2 + (-1)Debugging Checklist
If your solution fails:
- Check prefix array size: Should be
len(nums) + 1 - Check initialization: Should start with
[0] - Check formula: Should be
prefix[right + 1] - prefix[left] - Trace manually: Print prefix array and verify calculations
- Test edge cases: Empty array, single element, negative numbers
Visual Walkthrough
Building the Prefix Array
nums = [3, 1, 4, 1, 5]
Step 0: prefix = [0]
Step 1: num = 3
prefix = [0, 0+3] = [0, 3]
Step 2: num = 1
prefix = [0, 3, 3+1] = [0, 3, 4]
Step 3: num = 4
prefix = [0, 3, 4, 4+4] = [0, 3, 4, 8]
Step 4: num = 1
prefix = [0, 3, 4, 8, 8+1] = [0, 3, 4, 8, 9]
Step 5: num = 5
prefix = [0, 3, 4, 8, 9, 9+5] = [0, 3, 4, 8, 9, 14]
Final: prefix = [0, 3, 4, 8, 9, 14]Querying a Range
Query: sumRange(1, 3)
Formula: prefix[right + 1] - prefix[left]
= prefix[3 + 1] - prefix[1]
= prefix[4] - prefix[1]
= 9 - 3
= 6
Verify: nums[1] + nums[2] + nums[3]
= 1 + 4 + 1
= 6 ✓Practice Problems
Master off-by-one errors with these problems:
- Range Sum Query - Immutable (#303) - Basic template
- Range Sum Query 2D (#304) - 2D version with more indexing
- Running Sum of 1d Array (#1480) - Simpler variant
- Find Pivot Index (#724) - Running sum with careful indexing
FAQ
Q: Why not just use prefix[right] - prefix[left-1]?
A: This crashes when left = 0 (accessing index -1). You'd need a special case, making the code more complex and error-prone.
Q: Can I use 0-indexed prefix without padding?
A: Yes, but you'll need special cases:
if left == 0:
return prefix[right]
return prefix[right] - prefix[left - 1]This is more error-prone. The padding approach is cleaner.
Q: What if the problem uses 1-indexed arrays?
A: Some problems (like LeetCode #303) use 1-indexed results. Just adjust the return:
# If problem wants 1-indexed positions
return self.prefix[right + 1] - self.prefix[left] # Same formula!
# The padding handles this automaticallyQ: How do I remember the formula?
A: Think: "To include element at index right, I need the sum up to and including right, which is prefix[right + 1]."
Q: Does this work for 2D prefix sum?
A: Yes! The same padding principle applies. See 2D Prefix Sum Off-by-One.
Conclusion
Off-by-one errors in prefix sum are completely avoidable with the right approach.
Key takeaways:
- Always start with
prefix = [0]for padding - Use the formula:
sum(i, j) = prefix[j+1] - prefix[i] - Prefix array size:
len(nums) + 1 - No special cases needed for ranges starting at index 0
The correct template:
# Build
prefix = [0]
for num in nums:
prefix.append(prefix[-1] + num)
# Query
sum_range = prefix[right + 1] - prefix[left]Master this pattern, and you'll never submit a wrong answer due to off-by-one errors again. For more on prefix sum, see the complete guide and 1D template.
Next time you implement prefix sum, remember: pad with 0, use prefix[right+1] - prefix[left].
Want to Practice LeetCode Smarter?
LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.
Also compatible with Edge, Brave, and Opera
