π§© Maximum Subarray Problem β The Ultimate Guide (Brute Force + Kadaneβs Algorithm + Divide & Conquer)
The Maximum Subarray Problem is one of the most essential coding interview problems. It appears frequently in interviews for companies like FAANG, fintech giants, startups, and data engineering roles.
This problem builds your foundation in:
- Dynamic Programming
- Greedy thinking
- Divide & Conquer patterns
- Understanding how subarrays behave with positive and negative numbers
This guide explains the problem in simple terms, walks through the thought process, shows multiple approaches, and ends with clean, ready-to-use code.
Letβs dive in!
π Problem Statement
You are given an integer array nums.
Your task is to find the continuous subarray (not separate elements) that produces the largest sum, and return that sum.
π Example 1
Input:nums = [-2,1,-3,4,-1,2,1,-5,4]
Output:6
Explanation:
The subarray:
[4, -1, 2, 1]
gives the maximum sum.
Total = 4 + (-1) + 2 + 1 = 6
π Example 2
Input: [1]
Output: 1
π Example 3
Input: [5,4,-1,7,8]
Output: 23
π§ Understanding the Problem β How to Think About It
Before solving, letβs build intuition.
β 1. The subarray must be continuous
We are not allowed to pick random elements; we must pick elements that are next to each other.
β 2. Negative numbers reduce your sum
This is the biggest challenge. Too many negative numbers will destroy your sum.
β 3. If your running sum becomes negative, it harms future sums
Example:
If your sum becomes -10, and the next number is 5β¦
Should you continue?
-10 + 5 = -5 (bad)
Itβs better to start fresh from 5.
β 4. You must track two things
- The best sum ending at current index
- The best sum overall
These ideas lead us toward the famous Kadaneβs Algorithm.
But before that, letβs explore all approaches.
.
π Flowchart / Diagram for Maximum Subarray (Kadaneβs Algorithm)
ββββββββββββββββββββββββββββββ
β Start Algorithm β
βββββββββββββββββ¬βββββββββββββ
β
βΌ
ββββββββββββββββββββββββββ
β Initialize: β
β currentSum = nums[0] β
β maxSum = nums[0] β
βββββββββββ¬βββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββ
β Loop through array from i=1 β
βββββββββββββββββ¬βββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β For each nums[i]: β
β currentSum = max(nums[i], β
β currentSum + nums[i])β
βββββββββββββββββββββ¬βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββ
β Update maxSum = β
β max(maxSum, β
β currentSum) β
βββββββββββββ¬ββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Move to next element until end β
ββββββββββββββββββββ¬βββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββ
β Return maxSum (Answer) β
ββββββββββββββββββββββββββββββ
πͺ Approach 1: Brute Force (O(nΒ²))
π‘ Idea:
Check the sum of every possible subarray and pick the maximum.
π Why it works:
Because you literally check all possibilities.
π Why it’s bad:
Too slow for large arrays (10β΅ elements).
For interviews, this will get rejected.
β Brute Force Code
def maxSubArray_bruteforce(nums):
max_sum = float('-inf')
for i in range(len(nums)):
current_sum = 0
for j in range(i, len(nums)):
current_sum += nums[j]
max_sum = max(max_sum, current_sum)
return max_sum
β‘ Approach 2: Kadaneβs Algorithm (Optimized O(n) Solution)
This is the most efficient and most popular solution.
π― Intuition Behind Kadaneβs Algorithm
π₯ Key observation:
At every index:
You must choose between:
- Starting a new subarray
(if the current number is better than your running sum) - Continuing the previous subarray
(if adding the current number increases the sum)
We express this as:
currentSum = max(nums[i], currentSum + nums[i])
Then update global maximum:
maxSum = max(maxSum, currentSum)
π§ Why Does This Work?
Letβs break it down with emotions:
- If your past sum is positive, keep it (it helps you).
- If your past sum is negative, throw it away (it harms you).
This is exactly like choosing good friends (positive influence) and avoiding bad ones (negative influence).
You only keep what improves your future sum.
β Kadaneβs Algorithm Code
def maxSubArray(nums):
current_sum = nums[0]
max_sum = nums[0]
for i in range(1, len(nums)):
current_sum = max(nums[i], current_sum + nums[i])
max_sum = max(max_sum, current_sum)
return max_sum
π Step-by-Step Example (Kadaneβs Algorithm)
Input:
[-2,1,-3,4,-1,2,1,-5,4]
| Index | Num | currentSum | maxSum | Explanation |
|---|---|---|---|---|
| 0 | -2 | -2 | -2 | Start |
| 1 | 1 | 1 | 1 | Better to start fresh |
| 2 | -3 | -2 | 1 | Negative pulls sum down |
| 3 | 4 | 4 | 4 | New start |
| 4 | -1 | 3 | 4 | Continue |
| 5 | 2 | 5 | 5 | Continue |
| 6 | 1 | 6 | 6 | Best subarray here |
| 7 | -5 | 1 | 6 | Slight drop |
| 8 | 4 | 5 | 6 | Continue |
Final Answer = 6
π§© Approach 3: Divide & Conquer (O(n log n))
This approach is more complex but often asked as a follow-up.
It uses the same idea as merge sort:
Steps:
- Divide the array into two halves
- Conquer recursively for
- Left half
- Right half
- Combine by calculating:
- Maximum subarray that crosses the middle
- Final result =
max(left_result, right_result, crossing_result)
π― Why Does This Work?
When we split the array:
There are only 3 possible places where the max subarray can lie:
1οΈβ£ Entirely in the left half
2οΈβ£ Entirely in the right half
3οΈβ£ Crosses the middle (part left, part right)
We compute all three and return the maximum.
π How to Compute the Middle Crossing Subarray
To check crossing subarray:
- Start from middle and go left, collecting the best sum
- Start from middle+1 and go right, collecting the best sum
- Add both together
This gives the largest sum that βcrossesβ the middle point.
β Divide & Conquer Code
def maxCrossingSum(nums, left, mid, right):
# Include elements on left of mid
left_sum = float('-inf')
current = 0
for i in range(mid, left-1, -1):
current += nums[i]
left_sum = max(left_sum, current)
# Include elements on right of mid
right_sum = float('-inf')
current = 0
for i in range(mid+1, right+1):
current += nums[i]
right_sum = max(right_sum, current)
return left_sum + right_sum
def maxSubArrayDivide(nums, left, right):
# Base case: one element
if left == right:
return nums[left]
mid = (left + right) // 2
# Find max in left half, right half, and crossing
left_max = maxSubArrayDivide(nums, left, mid)
right_max = maxSubArrayDivide(nums, mid+1, right)
cross_max = maxCrossingSum(nums, left, mid, right)
return max(left_max, right_max, cross_max)
def maxSubArray_DnC(nums):
return maxSubArrayDivide(nums, 0, len(nums)-1)
π Comparison of All Approaches
| Approach | Time Complexity | Space | Difficulty | Useful For |
|---|---|---|---|---|
| Brute Force | O(nΒ²) | O(1) | Easy | Understanding subarrays |
| Kadaneβs | O(n) | O(1) | Medium | Best real-world solution |
| Divide & Conquer | O(n log n) | O(log n) | Hard | Learning recursion patterns |
π Final Summary
The Maximum Subarray problem teaches important lessons:
- How to handle negative values
- How to track continuous running sums
- How dynamic programming decisions are made
- How divide and conquer reduces large problems
The best possible solution is Kadaneβs Algorithm, which solves the problem in O(n) time with only constant memory.
Leave a Reply