The Quest Begins (The "Why")
Honestly, I used to stare at interview questions like “maximum subarray sum” and feel like I was trying to solve a Rubik’s cube blindfolded. I’d write two nested loops, watch the runtime blow up, and think, “There’s got to be a smarter way.” The problem seemed simple—pick a contiguous chunk of numbers that gives the biggest total—but the brute‑force approach felt like using a sledgehammer to crack a nut. I kept asking myself: Why does the best subarray ending at position i have to either extend the best subarray ending at i‑1 or start fresh at i? That nagging question pushed me to dig deeper, and what I found felt like uncovering a cheat code.
The Revelation (The Insight)
Here’s the magic: Kadane’s algorithm isn’t just a trick; it’s a direct manifestation of optimal substructure and overlapping subproblems—the heart of dynamic programming.
Think about any optimal subarray that ends at index i. There are only two possibilities:
- It includes the element at i‑1, meaning the optimal subarray ending at i‑1 is part of it.
- It starts exactly at i, discarding everything before because adding any prior sum would only make it smaller.
So the best sum ending at i is either nums[i] all by itself, or nums[i] + best_sum_ending_at_(i‑1). We don’t need to remember every subarray; we just need the best one that ends at the previous spot. That’s why we can keep a single running variable, update it in O(1) time per element, and still guarantee we’ve examined every candidate.
The moment I realized we were only carrying forward a single piece of state, it felt like Neo seeing the Matrix code—everything snapped into focus.
Wielding the Power (Code & Examples)
The “Before” – Brute Force (O(n²))
def max_subarray_brute(nums):
best = float('-inf')
for i in range(len(nums)):
cur = 0
for j in range(i, len(nums)):
cur += nums[j]
best = max(best, cur)
return best
Look at those two loops—yikes! For an array of 10⁵ elements you’d be doing billions of operations. Interviewers would politely (or not so politely) ask you to do better.
The “After” – Kadane’s Algorithm (O(n))
def max_subarray_kadane(nums):
# current_best holds the best sum ending at the previous index
current_best = global_best = nums[0] # handle all‑negative case
for x in nums[1:]:
# Either extend the previous subarray or start fresh at x
current_best = max(x, current_best + x)
global_best = max(global_best, current_best)
return global_best
Why this works:
-
current_bestimplements the recurrencebest_end_here[i] = max(nums[i], nums[i] + best_end_here[i‑1]). -
global_besttracks the maximum over allbest_end_here[i], which is exactly the answer.
That’s it—one pass, constant extra space.
Common Trap #1 – Resetting to Zero
If you write current_best = max(0, current_best + x), you’ll incorrectly return 0 for an all‑negative array (e.g., [-3, -2, -5]). The fix is to seed with the first element and never allow the sum to drop below the element itself, as shown above.
Common Trap #2 – Forgetting the First Element
Starting the loop at index 0 and initializing both variables to 0 fails when the best subarray is a single negative number. Always initialize with nums[0] (or handle the empty‑array edge case separately).
Interview Problem #1 – LeetCode 53: Maximum Subarray
Input:
[-2,1,-3,4,-1,2,1,-5,4]
Output:6(subarray[4,-1,2,1])
Just drop the array into max_subarray_kadane and you’re done.
Interview Problem #2 – Best Time to Buy and Sell Stock (One Transaction)
Input:
[7,1,5,3,6,4]
Output:5(buy at 1, sell at 6)
Transform the problem: compute daily price differences diff[i] = price[i+1] - price[i]. The max profit equals the max subarray sum of diff. Re‑use the same Kadane function:
def max_profit(prices):
if len(prices) < 2: return 0
diffs = [prices[i+1] - prices[i] for i in range(len(prices)-1)]
return max_subarray_kadane(diffs)
Again, O(n) time, O(1) extra space (you can even compute diffs on the fly).
Why This New Power Matters
Now you’ve got a tool that turns seemingly quadratic nightmares into linear victories. Any problem that asks for “the best contiguous segment” — whether it’s sums, profits, or even custom scores — can be tackled with the same two‑variable pattern. It’s not just about passing interviews; it’s about training your brain to spot optimal substructure everywhere. When you see a problem, ask: What’s the smallest piece of information I need to carry forward? If the answer is a single scalar, you’ve likely found a Kadane‑style solution.
I still remember the first time I cleared a medium‑level DP question in under a minute after internalizing this insight—it felt like unlocking a secret level in a game. Suddenly, the DP monster wasn’t scary; it was a friendly sidekick waiting for a command.
Your Turn
Try this: given an array of integers (both positive and negative), find the maximum sum of a subarray with at least one element and return the indices of that subarray. Extend Kadane to track start and end positions—share your solution in the comments!
Happy coding, and may your subarrays always be maximal! 🚀
Top comments (0)