Overview
Kadane's algorithm finds the maximum sum of a contiguous subarray in O(n) time and O(1) space. At each index it asks one question: is it better to extend the best subarray ending at the previous index, or to start fresh at this element?
It is the simplest example of dynamic programming on arrays: best ending here = max(nums[i], best ending before + nums[i]). Your repo's thumb rule captures it well: when you need one global best over all subarrays, think Kadane.
You walk along a path picking up coins (positive) and paying tolls (negative). If your running balance ever becomes negative, it only hurts whatever comes next, so you drop it and start counting again from the current spot, while remembering the best balance you ever had.
When to use it
- Maximum (or minimum) sum of a contiguous subarray.
- Values can be negative (otherwise the whole array is the answer).
- The answer depends on the best subarray ending at each position.
- Variants: maximum product, circular arrays, best stock profit.
Problem patterns it solves
Recognize it when: largest sum of any contiguous subarray.
- 53. Maximum Subarray
- 1749. Maximum Absolute Sum of Any Subarray
- 2606. Find the Substring With Maximum Cost
Recognize it when: subarray may wrap around the end; answer is max(normal, total - minimum subarray).
- 918. Maximum Sum Circular Subarray
Recognize it when: products where a negative flips the sign.
- 152. Maximum Product Subarray
Recognize it when: best gain between a buy and a later sell.
- 121. Best Time to Buy and Sell Stock
- 1014. Best Sightseeing Pair
Recognize it when: allow skipping one element; best submatrix via row compression.
- 1186. Maximum Subarray Sum with One Deletion
- 363. Max Sum of Rectangle No Larger Than K
Where it is used in real software
Finding the time window with the highest cumulative return, or the maximum drawdown (the minimum subarray of daily changes).
Finding the highest-scoring segment in a DNA sequence where each base contributes a positive or negative score.
Detecting the brightest region of a signal after subtracting a baseline, and the 2D variant finds the brightest rectangle.
Finding the period with the largest net growth in users or revenue from daily deltas.
Key terms
- current
- The best sum of a subarray that ends exactly at index i.
- best
- The best sum seen at any index so far (global answer).
- Restart
- When current + nums[i] < nums[i], begin a new subarray at i.
- Optimal substructure
- The best subarray ending at i extends the best ending at i - 1 or starts at i.
How it works, step by step
- 1Initialize with the first element
current = best = nums[0]. Do not use 0, or an all-negative array returns the wrong answer.
- 2For each next element
current = max(nums[i], current + nums[i]).
- 3Update the global best
best = max(best, current).
- 4Track indexes if needed
When you restart, record start = i; when best improves, record the start and end.
STEP 1current = -2, best = -2.
Trace of current and best
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
| i | nums[i] | current + nums[i] | current | Decision | best |
|---|---|---|---|---|---|
| 0 | -2 | - | -2 | start | -2 |
| 1 | 1 | -1 | 1 | restart | 1 |
| 2 | -3 | -2 | -2 | extend | 1 |
| 3 | 4 | 2 | 4 | restart | 4 |
| 4 | -1 | 3 | 3 | extend | 4 |
| 5 | 2 | 5 | 5 | extend | 5 |
| 6 | 1 | 6 | 6 | extend | 6 |
| 7 | -5 | 1 | 1 | extend | 6 |
| 8 | 4 | 5 | 5 | extend | 6 |
NOWi: 0 | nums[i]: -2 | current + nums[i]: - | current: -2 | Decision: start | best: -2
The maximum subarray sum is 6. A negative running sum can never help a future subarray, which is the whole insight behind restarting.
Implementation
function maxSubArray(nums) { let current = nums[0]; let best = nums[0]; for (let i = 1; i < nums.length; i++) { current = Math.max(nums[i], current + nums[i]); best = Math.max(best, current); } return best;} // Return the subarray boundaries toofunction maxSubArrayRange(nums) { let current = nums[0], best = nums[0]; let start = 0, bestStart = 0, bestEnd = 0; for (let i = 1; i < nums.length; i++) { if (nums[i] > current + nums[i]) { current = nums[i]; start = i; } else { current += nums[i]; } if (current > best) { best = current; bestStart = start; bestEnd = i; } } return { best, bestStart, bestEnd };} // 918. Circular: max(normal Kadane, total - min subarray)function maxSubarraySumCircular(nums) { let total = 0; let curMax = 0, bestMax = -Infinity; let curMin = 0, bestMin = Infinity; for (const x of nums) { curMax = Math.max(x, curMax + x); bestMax = Math.max(bestMax, curMax); curMin = Math.min(x, curMin + x); bestMin = Math.min(bestMin, curMin); total += x; } return bestMax < 0 ? bestMax : Math.max(bestMax, total - bestMin); // all negative}Complexity and performance
One pass.
Two variables.
All subarrays with running sums.
Also correct, rarely needed.
Trade-offs
Prefix sums answer 'sum equals k' counting problems; Kadane answers 'maximum sum' optimization in one pass with O(1) memory.
Sliding window requires a monotonic validity rule. With negatives and no size constraint, Kadane is the right tool.
Variants and related techniques
Replace max with min; used in the circular variant and maximum drawdown.
Combine prefix sums with the minimum prefix seen up to i - k.
Fix a pair of rows, compress columns into one array, and run Kadane: O(rows^2 x cols).
Common mistakes
- Initializing best = 0.
Fix: Start with nums[0] so an all-negative array returns its largest element.
- Circular variant when all numbers are negative.
Fix: total - min would give 0 (empty subarray); return bestMax instead.
- Maximum product without tracking the minimum.
Fix: A large negative times a negative becomes a large positive.
Interview questions
Why is it safe to drop a negative running sum?
Any subarray that continues after it would be larger without that negative prefix, so a negative prefix can never be part of an optimal future subarray.
How is Kadane dynamic programming?
dp[i] = best sum ending at i = max(nums[i], dp[i - 1] + nums[i]); the answer is max over all dp[i]. Kadane keeps only dp[i - 1], giving O(1) space.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 53. Maximum Subarray | Medium | Core algorithm. |
| 121. Best Time to Buy and Sell Stock | Easy | Running minimum. |
| 152. Maximum Product Subarray | Medium | Track max and min. |
| 918. Maximum Sum Circular Subarray | Medium | Total minus minimum. |
| 1186. Maximum Subarray Sum with One Deletion | Medium | Two DP states. |