Dynamic programming

O(n²)·O(n) space
Whole table

Drag to pan; pinch or Ctrl+scroll to zoom, which stops at the whole table; arrow keys pan once the picture has focus. The headers stay put while you pan.

position 0, which holds 10, not yet filledposition 1, which holds 22, not yet filledposition 2, which holds 9, not yet filledposition 3, which holds 33, not yet filledposition 4, which holds 21, not yet filledposition 5, which holds 50, not yet filledposition 6, which holds 41, not yet filledposition 7, which holds 60, not yet filledposition 0, which holds 10100position 1, which holds 22221position 2, which holds 992position 3, which holds 33333position 4, which holds 21214position 5, which holds 50505position 6, which holds 41416position 7, which holds 60607the longest run ending hererunlength→ number↓ run

The table has 1 row and 8 columns, and nothing has been worked out yet. Each cell looks back at every cell before it, not at a fixed few, which is the whole difference on this page.

The table has 1 row and 8 columns, and nothing has been worked out yet. Each cell looks back at every cell before it, not at a fixed few, which is the whole difference on this page.
Answer so far—

L(j) = 1 + max over i < j with a[i] < a[j] of L(i)

  1. 1every cell starts at 1, since any single number is an increasing run of length one
  2. 2look back at an earlier number that is smaller: one more than its cell is a candidate
  3. 3an earlier number that is not smaller cannot be extended, so skip it
  4. 4keep the best candidate, and remember where it came from
  5. 5walk back from the largest cell in the row, following what each cell remembered
  6. 6stop: the largest cell is the length, and the walk back is the subsequence
Cells filled
0
Cells read
0
Values written
0
Look-backs refused
0

Complexity

BestO(n²)
AverageO(n²)
WorstO(n²)
Extra spaceO(n)
n² / 2 at n=8 predicts 28; this run took 0.

Longest increasing subsequence

The cell for a position holds the length of the longest increasing subsequence that ends at that position. To work it out, look back at every earlier position; any whose number is smaller could be extended by this one, so take the best of those and add one. A position with nothing smaller before it starts a run of its own, of length one. The answer is the largest number anywhere in the row, which is not necessarily the last.

Its recurrence

L(j) = 1 + max over i < j with a[i] < a[j] of L(i)

When it is the right choice

Sorting out the longest consistent run in a sequence: patience sorting, the box-stacking and activity-chaining family of puzzles, and measuring how far a list is from being sorted. The quadratic version here is the one worth understanding first; there is an O(n log n) version that keeps a sorted list of best tails instead of a table, and it is faster and teaches less.

How it works

Worth noticing

Cost

Best
O(n²)
Average
O(n²)
Worst
O(n²)
Extra space
O(n)
Table
one dimension
Accepts
2 to 20 numbers, each from 0 to 99

The limits are pedagogical rather than technical: this tool keeps the whole table in every recorded step, so the shape of the table sets the size of the trace directly, and a run has to stay short enough to sit and watch. An input that would take more than three thousand steps on this algorithm is refused before a single step is generated, from a formula in the input sizes rather than by running it and finding out.

An unfilled cell is drawn differently from a cell holding a zero — no fill, a dashed outline, and no number at all — because early in a run that difference is most of the picture.

Worth comparing

All dynamic programming algorithms