Master Kadane's Algorithm for Maximum Subarray Sum
What is a Subarray?
A subarray is a contiguous part of any given array. For example, in array [1, 2, 3, 4], valid subarrays include:
- Single elements: [1], [2], [3], [4]
- Two elements: [1,2], [2,3], [3,4]
- Three elements: [1,2,3], [2,3,4]
- Full array: [1,2,3,4]
Mathematically, for an array of size n, total subarrays = n(n+1)/2. This quadratic growth makes brute-force approaches computationally expensive for large inputs.
Brute Force Approach
The simplest method calculates sums for all possible subarrays:
Generate all subarrays: Use nested loops
- Outer loop: Start index
ifrom 0 to n-1 - Middle loop: End index
jfromito n-1 - Inner loop: Calculate sum from
itoj
- Outer loop: Start index
Track maximum sum: Update a
max_sumvariable whenever a larger sum is found.
Time Complexity: O(n³) - Three nested loops make this inefficient for large arrays.
def brute_force(nums):
max_sum = float('-inf')
n = len(nums)
for i in range(n):
for j in range(i, n):
current_sum = 0
for k in range(i, j+1):
current_sum += nums[k]
max_sum = max(max_sum, current_sum)
return max_sum
Optimization Note: The inner loop can be eliminated by maintaining a running sum:
current_sum = 0
for j in range(i, n):
current_sum += nums[j]
max_sum = max(max_sum, current_sum)
This reduces time complexity to O(n²).
Kadane's Algorithm: The Optimized Solution
Kadane's algorithm solves the problem in O(n) time with O(1) space by intelligently tracking sums:
Core Insight
- If a subarray sum becomes negative, it cannot contribute to future maximum sums
- Reset the sum to zero whenever it dips below zero
Step-by-Step Logic
- Initialize
current_sum = 0andmax_sum = smallest possible value - For each number in the array:
- Add number to
current_sum - Update
max_sumifcurrent_sumexceeds it - If
current_sum < 0, reset it to 0
- Add number to
Handling Edge Cases
For all-negative arrays (e.g., [-3, -1, -2]), resetting to zero would return 0 (incorrect). Solution:
- Initialize
max_sum = nums[0]instead of negative infinity - Compare
current_sumandmax_sumbefore resetting
def kadanes_algorithm(nums):
current_sum = 0
max_sum = nums[0] # Critical for all-negative arrays
for num in nums:
current_sum += num
max_sum = max(max_sum, current_sum) # Update BEFORE reset
if current_sum < 0:
current_sum = 0 # Reset negative sums
return max_sum
Walkthrough Example
Array: [3, -4, 5, 4, -1, 7, -8]
| Step | num | current_sum | max_sum | Action |
|---|---|---|---|---|
| 1 | 3 | 3 | 3 | max_sum updated |
| 2 | -4 | -1 | 3 | Reset to 0 |
| 3 | 5 | 5 | 5 | max_sum updated |
| 4 | 4 | 9 | 9 | max_sum updated |
| 5 | -1 | 8 | 9 | - |
| 6 | 7 | 15 | 15 | max_sum updated |
| 7 | -8 | 7 | 15 | - |
Final max_sum = 15 (subarray [5, 4, -1, 7])
Why Kadane's Algorithm Works
This approach works because:
- Non-negative prefixes are preserved: Positive sums carry forward
- Negative prefixes are discarded: They only reduce subsequent sums
- Single-pass efficiency: Each element processed exactly once
Mathematical Proof: By induction, at each step, current_sum represents the maximum subarray sum ending at the current index.
Practical Applications
- Financial analysis: Maximizing profit in stock price timelines
- Data analytics: Finding most impactful contiguous data segments
- Image processing: Detecting brightest regions
Key Takeaways
- Brute force is acceptable for small arrays (n < 100)
- Kadane's algorithm is optimal for large datasets
- Edge matters: Handle all-negative arrays explicitly
- Real-world relevance: Used in genomic sequence analysis
Implementation Checklist
- Initialize
current_sum = 0,max_sum = first element - Iterate through each number:
a. Add number tocurrent_sum
b. Updatemax_sum = max(max_sum, current_sum)
c. Ifcurrent_sum < 0, reset to 0 - Return
max_sum
Advanced Resources
- Book: Introduction to Algorithms (Cormen) - Dynamic programming foundations
- Course: Grokking Dynamic Programming - Patterns for similar problems
- Practice: LeetCode Problem 53 - Test with custom edge cases
"Kadane's algorithm exemplifies how a simple insight - discarding detrimental prefixes - transforms O(n²) problems into O(n) solutions." - Algorithm Design Manual
Which step do you anticipate being most challenging when implementing this? Share your experience in the comments!