Module 1: Arrays, Hashing & Prefix Sums·Tutorial 3 of 23 (Step 1.3)
All Tutorials·DSA Roadmap·9 Problems · ~6 hrs

1.3 Prefix Sums & Kadane's Subarray Algorithm

Learn what a contiguous subarray is, how Prefix Sums answer any range sum in O(1), and how Kadane's Algorithm finds the maximum subarray sum in one pass.

01 Read the story: What & Why
02 Follow the drawing: Visual stepper
03 Practice code: 4 languages + problems

1. What Are Prefix Sums & Kadane's Algorithm?

First, let's clarify a word that appears in hundreds of interviews:

  • A Subarray is a contiguous (unbroken) slice of an array. For [3, 1, -2, 5], [1, -2, 5] is a subarray, but [3, -2, 5] is not (because it skipped 1).

When problems ask about sums of subarrays, two foundational techniques solve 90% of them:

  1. Prefix Sum (P[]): A precomputed array of running totals from index 0 up to each index i.
  2. Kadane's Algorithm: A single-pass greedy/DP rule that tracks the best subarray sum ending at the current index.

2. Why Do We Need Them & How Do They Work?

Part A: Why Prefix Sums Exist (O(1) Range Queries)

Suppose someone gives you an array of 100,000 numbers and asks 50,000 questions: "What is the sum from index L to index R?" Looping from L to R for every question takes O(N * Q) time. Instead, build a prefix array P of length N + 1 where P[0] = 0 and P[i + 1] = P[i] + nums[i]. Now, to find the sum from L to R, take the total up to R (P[R + 1]) and subtract the prefix before L (P[L]):

sum(L .. R) = P[R + 1] - P[L]

Visual: 1D Prefix Sum — Any Subarray Sum(L..R) = P[R + 1] - P[L] in O(1)
nums[]31-254P[]0342711sum(nums[1..3]) = 1 + (-2) + 5 = P[4] - P[1] = 7 - 3 = 4

Part B: Prefix Sum + Hash Map (Subarray Sum Equals K)

What if the problem asks: "How many subarrays add up to k?" and the array has negative numbers? If curr_prefix - old_prefix == k, then old_prefix == curr_prefix - k! So as you walk through the array keeping a running sum curr, store how many times each prefix sum has appeared in a Hash Map (counts = {0: 1}). At each step, counts[curr - k] tells you in O(1) how many valid subarrays end right here!

Part C: Why Kadane's Algorithm Works (Maximum Subarray)

To find the contiguous subarray with the largest sum, ask one question as you stand at x: "Is my previous running sum curr positive or negative?"

  • If curr < 0, adding a negative number to x only makes x smaller! Throw curr away and start fresh at x.
  • If curr >= 0, keep extending: curr = curr + x.

In one formula: curr = max(x, curr + x).

Visual: Kadane's Decision Rule — Reset Running Sum Whenever It Drops Below 0
num: -2curr=-2Startnum: 1curr=1Reset! (-2 < 0)num: -3curr=-2Extend (1-3)num: 4curr=4Reset! (-2 < 0)num: -1curr=3Extend (4-1)num: 2curr=5Extend (3+2)num: 1curr=6 ★Max Best = 6curr = max(x, curr + x) ──► A negative prefix never helps a future subarray!

Step Through the Visual Drawing: Prefix Range Queries & Kadane's Reset

Click Next below to step through both O(1) range subtraction and Kadane's negative-prefix reset rule:

The Hand-Drawn Step-by-Step Walkthrough
Step 1 / 3

Interactive Step-by-Step Trace: Prefix Sum Range Queries & Kadane's Reset

See how running totals answer any subarray sum in O(1) subtraction:

Step 1: Build the Prefix Array in One O(N) Pass
pref[0]0
pref[1]3
pref[2]4
pref[3]8
pref[4]13Total
nums = [3, 1, 4, 5] -> pref = [0, 3, 4, 8, 13]

Leading 0 at pref[0] represents an empty prefix before index 0.

✎ Remember this: pref[i + 1] stores the sum of nums[0..i].

3. Basic Operations & Walkthroughs (All 4 Languages)

# 1. Build 1D Prefix Sum & Query Any Range [L..R] in O(1)
nums = [3, 1, -2, 5, 4]
P = [0] * (len(nums) + 1)
for i, x in enumerate(nums):
  P[i + 1] = P[i] + x

sum_1_to_3 = P[3 + 1] - P[1]  # 7 - 3 = 4

# 2. Prefix Sum + Hash Map (Subarray Sum Equals K)
def subarray_sum(nums: list[int], k: int) -> int:
  counts = {0: 1}  # Base case: empty prefix has sum 0
  curr = ans = 0
  for x in nums:
      curr += x
      ans += counts.get(curr - k, 0)
      counts[curr] = counts.get(curr, 0) + 1
  return ans

# 3. Kadane's Algorithm (Maximum Subarray Sum in O(N) time, O(1) space)
def max_subarray(nums: list[int]) -> int:
  curr = best = nums[0]
  for x in nums[1:]:
      curr = max(x, curr + x)
      best = max(best, curr)
  return best

4. Core Interview Patterns & Common Traps

Pattern: Prefix Sum + Hash Map (Count Subarrays with Sum == K)

Use whenever an array can contain negative numbers (so Sliding Window fails!) and you need to count or find subarrays with target sum K.

counts = {0: 1}  # Never forget {0: 1} for subarrays starting at index 0!
curr = ans = 0
for x in nums:
  curr += x
  ans += counts.get(curr - k, 0)
  counts[curr] = counts.get(curr, 0) + 1
Operation / PatternTimeSpaceNotes
1D Prefix Sum Range QueryO(1)O(N)O(N) preprocessing once; O(1) per query
2D Prefix Sum Rectangle QueryO(1)O(R * C)Inclusion-Exclusion: P[r2][c2] - P[r1][c2] - P[r2][c1] + P[r1][c1]
Prefix Sum + Hash MapO(N)O(N)Works even with negative numbers; initialize {0: 1}
Kadane's Max SubarrayO(N)O(1)Initialize best = nums[0] to handle all-negative arrays

5. Practice On Your Own (Curated Submodule Problems)

0 / 9 Solved
StatusProblemDifficultyComplexityHint?Links & Notes
Product of Array Except Self
1D & 2D Prefix Sums
Medium
T: O(N)
S: O(1)
Solve
Subarray Sum Equals K
1D & 2D Prefix Sums
Medium
T: O(N)
S: O(N)
Solve
Range Sum Query - Immutable
1D & 2D Prefix Sums
Easy
T: O(1) query
S: O(N)
Solve
Range Sum Query 2D - Immutable
1D & 2D Prefix Sums
Medium
T: O(1) query
S: O(R * C)
Solve
Continuous Subarray Sum
1D & 2D Prefix Sums
Medium
T: O(N)
S: O(min(N, K))
Solve
Subarray Sums Divisible by K
1D & 2D Prefix Sums
Medium
T: O(N)
S: O(K)
Solve
Maximum Subarray
Kadane's Subarray Accumulation
Medium
T: O(N)
S: O(1)
Solve
Best Time to Buy and Sell Stock
Kadane's Subarray Accumulation
Easy
T: O(N)
S: O(1)
Solve
Maximum Sum Circular Subarray
Kadane's Subarray Accumulation
Medium
T: O(N)
S: O(1)
Solve