AlgoInsight

Free lesson · DSA Mastery - Interview Prep, End to End

Introduction to Kadane's Algorithm

Medium5 min readdsakadane-s-algorithm

Introduction to Kadane's Algorithm

Kadane's algorithm is the canonical answer to one of the most-asked interview questions in existence: what is the largest sum you can get from a contiguous subarray? It solves that in a single O(n) pass with O(1) memory, and the reasoning behind it - a tiny running-state decision made at every element - generalizes into an entire family of "best contiguous run" problems. If sliding window (Module 12) is about maintaining an explicit [left, right] range, Kadane is about something subtler: never tracking the window's boundaries at all, just the best run ending right here.

This introduction lays out the core insight, the running-state recurrence, the relationship to prefix sums, and the variants - products, circular arrays, deletions, turbulence - that make up the rest of the module.

The One Decision Kadane Makes

Walk the array left to right. At each element, ask a single question about the best contiguous subarray that ends at this exact position:

"Should I extend the best run ending at the previous element, or start fresh from here?"

You start fresh exactly when the previous best run was a liability - when its sum was negative, dragging you down. Otherwise you extend. Formally, letting best[i] be the maximum sum of a subarray ending at index i:

best[i] = max(nums[i], best[i-1] + nums[i])

The global answer is max(best[i]) over all i. Because best[i] depends only on best[i-1], you don't need an array - a single running variable suffices, giving O(1) space.

graph TD
    A["At element nums[i]"] --> B{"best so far ending at i-1<br/>positive?"}
    B -->|Yes| C["Extend:<br/>best = best + nums[i]"]
    B -->|No| D["Start fresh:<br/>best = nums[i]"]
    C --> E["answer = max(answer, best)"]
    D --> E
    E --> F["move to i+1"]

    style A fill:#4338ca,stroke:#6366f1,color:#f1f5f9
    style B fill:#b45309,stroke:#f59e0b,color:#f1f5f9
    style C fill:#16a34a,stroke:#10b981,color:#f1f5f9
    style D fill:#dc2626,stroke:#ef4444,color:#f1f5f9
    style E fill:#16a34a,stroke:#10b981,color:#f1f5f9
    style F fill:#4338ca,stroke:#6366f1,color:#f1f5f9
This diagram shows the single decision Kadane makes at each element. If the best run ending at the previous position has a positive sum, we extend it by adding the current element. Otherwise we start a fresh run at the current element. After deciding, we update the global answer with the running best.

Interactive animation: On [1, -3, 2, 3, -4] the run extends while it helps, starts fresh at 2 when the run behind it is -2, and the best is 5.

Why "Ending Here" Is the Magic

The trick that makes Kadane work is reframing the problem. "Find the max-sum subarray anywhere" sounds like it requires considering all O(n²) subarrays. But every subarray ends somewhere. So if you can compute, for each position, the best subarray that ends exactly there, then the overall best is simply the largest of those n values.

And the best subarray ending at i has a beautiful recursive structure: it's either just nums[i] alone, or it's nums[i] glued onto the best subarray ending at i-1. There's no third option - anything ending at i must include nums[i], and whatever precedes it is some subarray ending at i-1 (or nothing). That's the whole algorithm.

Interactive animation: Four runs end at index 3, and the best of them is the 3 glued onto the best run ending at index 2.

The Running-State Pattern

Kadane is the archetype of a broader pattern: carry a small running state, make a local decision at each element, update a global answer. This pattern recurs across the module with different state:

The lesson the module teaches: once you see a "best contiguous run" problem, ask what minimal state, carried element to element, lets me make the local decision? That state is the heart of every Kadane variant.

Interactive animation: Every variant in the module carries a different small state, and only the circular one runs Kadane twice.

Relationship to Prefix Sums

Kadane is deeply connected to prefix sums (Module 11). The sum of a subarray (i, j] is P[j] - P[i], where P is the prefix-sum array. Maximizing that over all i < j means, for each j, subtracting the minimum prefix seen so far:

maxSubarray = max over j of ( P[j] - min(P[0..j-1]) )

That's literally Kadane in prefix-sum clothing: "best subarray ending at j" equals "current prefix minus the smallest earlier prefix." Both views give O(n); the running-variable form is just leaner. Keeping this duality in mind helps when a variant is easier to reason about in one frame than the other - Maximum Sum Circular Subarray, for instance, leans on the prefix/total-sum view.

graph LR
    A["Kadane view:<br/>best run ending here"] --- B["same answer"]
    B --- C["Prefix view:<br/>P[j] - min prefix before j"]

    style A fill:#4338ca,stroke:#6366f1,color:#f1f5f9
    style B fill:#16a34a,stroke:#10b981,color:#f1f5f9
    style C fill:#4338ca,stroke:#6366f1,color:#f1f5f9
This diagram shows the duality between Kadane's running-state view and the prefix-sum view. Kadane tracks the best run ending at each position; the prefix view computes the current prefix sum minus the smallest earlier prefix. Both produce the same maximum-subarray answer.

Interactive animation: The same 5 as the biggest climb on the prefix staircase: P[4] - P[2] = 3 - (-2).

When to Reach for Kadane

Kadane fits when all of these hold:

The classic signal phrases: "maximum/minimum sum subarray," "largest product of a contiguous run," "best contiguous … such that …." If the problem adds a twist - wraparound, one allowed deletion, alternating signs - it's usually still Kadane, just with richer state.

Interactive animation: A contiguous run, an aggregate, and a local decision with a little carried state: all three, and it is Kadane.

What Kadane Is Not For

What This Module Covers

The module is organized by how far each problem stretches the core idea:

Each problem walks the brute-force → Kadane arc, so you see why the running-state decision is correct, not just that it works. By the end, the recurrence best = max(nums[i], best + nums[i]) and its variations should be reflexive.

Let's begin with the problem that defines the technique: Maximum Subarray, where the single running-best decision is laid bare.

Back to DSA Mastery - Interview Prep, End to End