Hello! Welcome to the final lesson in our module on "High-ROI Interview Patterns."
In our last lesson, we mastered the sliding window technique, an efficient pattern for finding a contiguous subarray or substring that satisfies a certain property. We learned to "slide" a window across an array, updating our calculations incrementally to achieve a linear-time solution.
Today, we'll tackle a different kind of subarray problem using another essential, high-ROI pattern: prefix sums. While the sliding window is great for finding an optimal subarray, prefix sums are designed for scenarios where you need to answer multiple queries about the sum of different subarrays, and you need to do it fast.
Your learning outcome for this lesson is to implement and apply prefix sums to answer range query problems in O(1) time. This is a classic time-space tradeoff that interviewers love to see, as it demonstrates an understanding of pre-computation to optimize repetitive tasks.
1. The Problem: Handling Multiple Range Sum Queries
Imagine you are given an array of numbers and are asked to calculate the sum of elements between various pairs of indices [left, right]. This is known as a range sum query.
A simple approach would be to loop from left to right and add up the numbers for each query.
- For a single query: The time complexity is
O(right - left), which in the worst case isO(n). - For
Qqueries: The total time complexity becomesO(n * Q).
In a typical interview setting, n and Q can be up to 10,000 or more, making an O(n * Q) solution too slow. This is where we need a more intelligent approach.
Range Sum Query Immutable - Leetcode 303 - Python
To understand the problem and why the naive approach falls short, let's watch the beginning of the NeetCodeIO video on 'Range Sum Query - Immutable'.
Watch from the beginning until 02:14. This section clearly defines the problem and explains why both the simple O(n) per query and an O(n²) pre-computation approach are inefficient.
2. The Solution: Pre-computation with Prefix Sums
The key to optimizing this problem is to perform a one-time pre-computation. We can create an auxiliary array, often called prefix_sum, that stores the cumulative sum of the original array at each index.
A prefix sum at index i is the sum of all elements from the beginning of the array up to and including index i.
prefix_sum[i] = nums[0] + nums[1] + ... + nums[i]
We can build this array in a single pass, with each new prefix sum being the previous prefix sum plus the current number:
This pre-computation step takes O(n) time and requires O(n) extra space.
Let's visualize how this array is built.

A Small but Important Trick: Padding with a Zero
In practice, it's highly convenient to make the prefix sum array one element longer than the input array and initialize the first element to 0. This simplifies the formula for querying and elegantly handles edge cases where the range starts at index 0.
If nums = [-2, 0, 3], our padded prefix sum array would be [0, -2, -2, 1].
prefix[0] = 0prefix[1] = prefix[0] + nums[0] = 0 + (-2) = -2prefix[2] = prefix[1] + nums[1] = -2 + 0 = -2prefix[3] = prefix[2] + nums[2] = -2 + 3 = 1
With this structure, prefix[i] now stores the sum of the first i elements of nums.
3. Answering Queries in O(1) Time
Once we have our pre-computed prefix sum array, how do we find the sum of elements between indices left and right (inclusive)?
The sum of elements from index left to right is the total sum up to right minus the total sum up to left - 1.
Using our padded prefix sum array, the formula is beautifully simple:
prefix_sum[right + 1]gives the cumulative sum up to and includingnums[right].prefix_sum[left]gives the cumulative sum of all elements beforenums[left].
Subtracting the two leaves us with exactly the sum of nums[left] through nums[right]. Since this involves just two array lookups and one subtraction, each query takes O(1) time.
Guide to Prefix Sum/Cumulative Sum Technique in Python
This article provides a clear, well-commented Python implementation and a great real-life analogy for the prefix sum technique.
Read the sections 'How to Solve This Efficiently?', 'Why is this O(1)?', and the final 'Summary'. Focus on the Python implementation of the NumArray class and the explanation of the time-space tradeoff.
Now, let's see this logic applied in a video walkthrough, which also covers the edge case for when the range starts at index 0.
Range Sum Query Immutable - Leetcode 303 - Python
The rest of the NeetCodeIO video demonstrates exactly how to use the prefix sum array to answer queries and provides a full Python implementation.
Watch from 02:14 to the end. Pay close attention to the formula prefix[right] - prefix[left-1] and how the code handles the case where left is 0.
4. Implementation Template
Here is a template for the NumArray class, which is how this problem (LeetCode 303) is often presented in interviews. Your background in OOP should make this class-based structure very familiar.
class NumArray:
def __init__(self, nums: list[int]):
# Initialize a prefix sum array with a leading zero.
self.prefix_sum = [0] * (len(nums) + 1)
# Pre-compute the prefix sums in O(n) time.
for i in range(len(nums)):
self.prefix_sum[i+1] = self.prefix_sum[i] + nums[i]
def sumRange(self, left: int, right: int) -> int:
# Calculate the sum in O(1) time using the pre-computed array.
# Note: self.prefix_sum is 1-indexed relative to the original array.
return self.prefix_sum[right + 1] - self.prefix_sum[left]
# Example Usage:
# nums = [-2, 0, 3, -5, 2, -1]
# numArray = NumArray(nums)
# print(numArray.sumRange(0, 2)) # Output: 1
# print(numArray.sumRange(2, 5)) # Output: -1
Test your understanding!
Given the array nums = [1, 2, 3, 4, 5]:
- What would the padded prefix sum array look like?
- Using your prefix sum array, what is the result of
sumRange(1, 3)? Show the calculation.
Show answer
-
The prefix sum array would be:
[0, 1, 3, 6, 10, 15].prefix[0] = 0prefix[1] = 0 + 1 = 1prefix[2] = 1 + 2 = 3prefix[3] = 3 + 3 = 6prefix[4] = 6 + 4 = 10prefix[5] = 10 + 5 = 15
-
To calculate
sumRange(1, 3), which corresponds tonums[1] + nums[2] + nums[3] = 2 + 3 + 4 = 9, we use the formula:prefix_sum[right + 1] - prefix_sum[left]prefix_sum[3 + 1] - prefix_sum[1] = prefix_sum[4] - prefix_sum[1] = 10 - 1 = 9.
5. Advanced Application: Combining with Hash Maps
The prefix sum pattern becomes even more powerful when combined with other data structures. A very common interview problem is "Subarray Sum Equals K," which asks for the number of contiguous subarrays that sum to a target k.
The key insight is:
If sum(i, j) = k, then prefix[j] - prefix[i-1] = k.
Rearranging this gives: prefix[i-1] = prefix[j] - k.
This means that as we iterate through the array and calculate the current prefix sum prefix[j], we can ask: "How many times have we previously seen a prefix sum equal to prefix[j] - k?" We can answer this question efficiently by storing the counts of all previously seen prefix sums in a hash map.
This is a fantastic example of combining two patterns and serves as a great bridge to our next module on hashing.
Coding Interview Patterns - Prefix Sum | 10 different problems in a single video
Let's watch a brief segment that explains this advanced technique. This will give you a glimpse into how fundamental patterns can be composed to solve more complex problems.
Watch from 13:49 to 19:40. Focus on the core formula (prefix_sum[j] - k = prefix_sum[i-1]) and how a hash map is used to store and look up past prefix sums.
Conclusion
Congratulations on completing the module on high-ROI interview patterns! You've now added prefix sums to your arsenal, a crucial technique for efficiently handling range-based queries on arrays.
Key Takeaways:
- Core Idea: Prefix sums involve a one-time pre-computation (
O(n)time,O(n)space) to create a cumulative sum array. - O(1) Queries: This pre-computation allows any subsequent range sum query to be answered in constant time (
O(1)). - The Formula: The sum of
nums[left...right]isprefix_sum[right+1] - prefix_sum[left]when using a 0-padded prefix sum array. - Time-Space Tradeoff: This pattern is a classic example of using extra space to achieve a significant speedup in time complexity, a concept highly valued in system design and algorithm interviews.
- Beyond Sums: The concept can be extended to products, XORs, and combined with other data structures like hash maps to solve a wider variety of problems.
In our next lesson, we will begin a new module, "Hashing for Efficient Lookups." We'll dive deep into how hash maps and hash sets work, and how they provide O(1) average time complexity for lookups, insertions, and deletions, making them one of the most versatile tools in a programmer's toolkit.