AlgoVerse

Maximum subarray (Kadane)

Find the contiguous range with the largest sum in one pass: whenever the running sum turns negative, drop it and start over.

In an array of positive and negative numbers (say, daily price changes), find the contiguous range with the largest sum.

Read the full explanation ↓
Input:
n=16PDF export

Sixteen daily price changes; the best range is a[7..10] with sum 43.

  1. def max_subarray(a):
  2. best = a[0]
  3. best_lo = 0
  4. best_hi = 0
  5. cur = a[0]
  6. cur_lo = 0
  7. for i in range(1, len(a)):
  8. if cur < 0:
  9. cur = a[i]
  10. cur_lo = i
  11. else:
  12. cur = cur + a[i]
  13. if cur > best:
  14. best = cur
  15. best_lo = cur_lo
  16. best_hi = i
  17. return best, best_lo, best_hi

Invariant: cur is the largest sum of a subarray ending exactly at i, and best is the largest sum of any subarray up to i.

Start

130-31-252203-34-165-236187208-791210-511-22121513-414715

Local variables

Orange = changed in this step

a list

13-3-2520-3-16-231820-712-5-2215-47

Call stack

  1. max_subarray()line 1
Step 1 of 79
Black = restart, extend · Orange = key stepcompare: 0/30 · extend: 0/13 · restart: 0/2 · new_best: 0/3

    How the work grows with input size

    Average of 12 random graphs per n (fixed seeds). Hollow marker = the input on screen.

    • comparisons
    • current input (n=16)
    010203046810121416n = number of itemscomparisons
    Show as a table
    ncomparisons
    46
    610
    814
    1018
    1222
    1426
    1630
    Explanation

    The problem

    In an array of positive and negative numbers (say, daily price changes), find the contiguous range with the largest sum.

    Kadane's idea

    For each position i, cur is the largest sum of a subarray that ends exactly at i. It has two choices: continue the previous subarray with a[i], or start over from a[i]. If cur is negative, continuing only hurts, so we start over. best is the largest cur seen so far.

    Cost

    One pass: O(n) time and O(1) memory. CLRS solves the same problem with divide and conquer in O(n log n); Kadane shows that a dynamic-programming idea makes it linear.

    What to watch in the trace

    • The blue band is the best range so far; the cur_lo arrow is where the current run started, and i is the current position.
    • On "starting over", watch cur_lo jump forward after the big drop.