Cheat Sheet

All of algorithms on a few pages

Five cheat sheets you can keep open while you study, or print for review: asymptotic notation, sums and recurrences, the design strategies with runnable templates, the complexity of every algorithm on this site, and the Forge Pseudocode language reference.

Acronyms used on this page: Traveling Salesman Problem (TSP), Dynamic Programming (DP), Greatest Common Divisor (GCD), Depth-First Search (DFS), Breadth-First Search (BFS), Minimum Spanning Tree (MST), Binary Search Tree (BST), Adelson-Velsky–Landis tree (AVL), Longest Common Subsequence (LCS), Knuth–Morris–Pratt (KMP), Directed Acyclic Graph (DAG), Strongly Connected Components (SCC), Longest Increasing Subsequence (LIS), Least Recently Used (LRU), Least Common Multiple (LCM), Boolean satisfiability (SAT), First-Fit Decreasing (FFD), input/output (I/O), deterministic Polynomial time (P), Nondeterministic Polynomial time (NP).

📈 Cheat sheet 1 of 5

Asymptotics

View as Markdown on GitHub ↗

Use it when you need to compare two running times, prove a bound, or say which efficiency class an algorithm is in. Everything here follows Levitin Chapter 2 (§2.1–2.2), re-expressed with our own examples.


1. The three notations in one table

Let t(n) be the running time (or basic-operation count) and g(n) a simple comparison function like n2.

NotationRead it asFormal definition (there exist c > 0 and n0 such that for all n ≥ n0)Think of it as
t(n) ∈ O(g(n))"big-oh": grows no faster than gt(n) ≤ c g(n)t ⪯ g — an upper bound
t(n) ∈ Ω(g(n))"big-omega": grows at least as fast as gt(n) ≥ c g(n)t ⪰ g — a lower bound
t(n) ∈ Θ(g(n))"big-theta": grows at the same rate as gc2 g(n) ≤ t(n) ≤ c1 g(n)t ≈ g — a tight bound
  • Θ(g) = O(g)∩Ω(g): to prove Θ, prove both directions.
  • The constants c, n0 are yours to choose. Any that work are fine; they do not have to be the smallest.
  • Only large n matters. Nothing is promised for n < n0 (that is why a Θ(n2) sort can beat a Θ(n log n) sort on small arrays).

Worked proof. Show ½n(n − 1) ∈ Θ(n2). Upper: ½n(n − 1) = ½n2 − ½n ≤ ½n2 for all n ≥ 0, so c1 = ½. Lower: ½n2 − ½n ≥ ½n2 − ½n·½n = ¼n2 once n ≥ 2, so c2 = ¼, n0 = 2. ∎

2. Rules you use every day

RuleStatementExample
Constant factors vanishc·t(n) ∈ Θ(t(n)) for any constant c > 05n2 ∈ Θ(n2)
Sum rule (the bigger part wins)If t1 ∈ O(g1) and t2 ∈ O(g2) then t1 + t2 ∈ O(max {g1, g2})sort (n log n) then scan (n) ⇒ O(n log n)
Polynomialsaknk + … + a0 ∈ Θ(nk) when ak > 03n3 − 100n2 + 7 ∈ Θ(n3)
Log base doesn't matterloga n = logb n/logb a, a constant multiplelog2 n ∈ Θ(log10 n)
Transitivityf ∈ O(g) and g ∈ O(h) ⇒ f ∈ O(h)n ∈ O(n log n) ⊆ O(n2)
Exponent bases do matteran ∈ o(bn) when a < b2n is much smaller than 3n
Log of a powerlog(nk) = k log n ∈ Θ(log n)log n100 ∈ Θ(log n)

3. The limit rule — the fastest way to compare two functions

Compute

limn→∞ t(n)/g(n)
LimitConclusion
0t has a smaller order of growth: t ∈ O(g) but t ∉ Θ(g)
a constant c > 0same order: t ∈ Θ(g)
∞t has a larger order of growth: t ∈ Ω(g) but t ∉ Θ(g)

(If the limit does not exist, fall back on the definitions. That almost never happens with algorithm running times.)

L'Hôpital's rule

If t(n) → ∞ and g(n) → ∞ and the derivatives exist, then

limn→∞ t(n)/g(n) = limn→∞ t′(n)/(g′(n))

Example — log2 n vs. √n. Derivatives: (log2 n)′ = 1/(n ln 2) and (√n)′ = 1/(2√n). Ratio: 2√n/(n ln 2) = 2/(ln 2·√n) → 0. So every logarithm grows slower than every square root (in fact slower than nε for any ε > 0).

Stirling's formula

n! ≈ √(2πn) (n/e)n

Two consequences you will use:

  • log2 n! ∈ Θ(n log n) — this is why no comparison sort can beat n log n (Chapter 11).
  • n! grows faster than an for every fixed a: lim n!/2n = ∞.

Example. Compare n! with 2n using Stirling: n!/2n ≈ √(2πn)(n/(2e))n → ∞ because n/(2e) > 1 once n > 5. ∎

4. Handy identities

  • alogb n = nlogb a (turns the Master Theorem's alogb n leaves into a power of n)
  • logb(xy) = logb x + logb y, logb(x/y) = logb x − logb y, logb xk = k logb x
  • 2log2 n = n, and the number of bits of n is ⌊log2 n⌋ + 1
  • ⌊x⌋ ≤ x < ⌊x⌋ + 1 and ⌈x⌉ − 1 < x ≤ ⌈x⌉
  • Harmonic numbers: 1 + ½ + … + 1/n = Hn ≈ ln n + 0.5772

5. The basic efficiency classes

Values below are rounded; "fits in about 1 second" assumes about 108 simple operations per second.

ClassNamen = 10n = 103n = 106Largest n in about 1 sTypical algorithms
1constant111anyarray access, push/pop, hash lookup (expected)
log nlogarithmic3.31020anybinary search, balanced-tree operations, exponentiation by squaring
nlinear10103106∼ 108sequential search, maximum element, counting sort (small range)
n log nlinearithmic331042·107∼ 5·106mergesort, heapsort, quicksort (average), closest pair (divide-and-conquer)
n2quadratic1021061012∼ 104selection, bubble and insertion sort; all pairs; element uniqueness by brute force
n3cubic1031091018∼ 500definition-based matrix multiplication, Floyd, Warshall, Gaussian elimination
2nexponential10310301—∼ 26all subsets: knapsack by exhaustive search, subset-sum, Tower of Hanoi moves
n!factorial3.6·106——∼ 11all permutations: Traveling Salesman Problem (TSP) by exhaustive search, assignment by exhaustive search

Order from slowest-growing to fastest: 1 < log n < √n < n < n log n < n2 < n3 < 2n < n! < nn

6. Common traps

  1. Big-O is not "the worst case." O/Ω/Θ describe functions. You can give a Θ bound for the best case, the worst case or the average case separately.
  2. "O(n²)" is not a promise of slowness. n ∈ O(n2) is true — just not tight. Use Θ when you mean "exactly this rate".
  3. Input size is the size, not the value. For a number n, the size is b = ⌊log2 n⌋ + 1 bits, so a loop running n times is exponential in b.
  4. Drop constants only at the end. When you count operations, keep the exact sum; simplify to Θ last.
  5. Don't compare exponents of different bases by eye: 4n = (2n)2 is not Θ(2n).
∑ Cheat sheet 2 of 5

Sums & Recurrences

View as Markdown on GitHub ↗

Use it when you have turned a loop into a sum or a recursive algorithm into a recurrence and now need a closed form. The content matches what Levitin collects in Appendix A (sums) and Appendix B (recurrences), written in our own words with our own worked examples.


1. Sum formulas to know by heart

#SumClosed formOrder
S1∑i=lu 1u − l + 1—
S2∑i=1n i = 1 + 2 + … + nn(n + 1)/2Θ(n2)
S3∑i=1n i2n(n + 1)(2n + 1)/6Θ(n3)
S4∑i=1n ik≈ (nk+1)/(k + 1)Θ(nk+1)
S5∑i=0n ai (for a ≠ 1)(an+1 − 1)/(a − 1)Θ(an) if a > 1
S6∑i=0n 2i2n+1 − 1Θ(2n)
S7∑i=1n i 2i(n − 1)2n+1 + 2Θ(n2n)
S8∑i=1n 1/i (harmonic)≈ ln n + 0.5772Θ(log n)
S9∑i=1n log i = log n!≈ n log nΘ(n log n)
S10∑i=0n−1(n − 1 − i)n(n − 1)/2Θ(n2)

Quick checks with n = 4: S2 gives 10, S3 gives 30, S6 (with n = 3) gives 15, S7 gives 3·32 + 2 = 98 ✔.

2. Manipulation rules

  • Constant factor out: ∑ c ai = c ∑ ai
  • Split a sum of terms: ∑(ai±bi) = ∑ ai±∑ bi
  • Split the range: ∑i=lu ai = ∑i=lm ai + ∑i=m+1u ai for l ≤ m < u
  • Telescoping: ∑i=lu(ai − ai−1) = au − al−1
  • Shift the index: ∑i=1n ai−1 = ∑j=0n−1 aj (substitute j = i − 1)
  • Bounding instead of solving: ∑i=1n f(i) ≤ n·max f; for increasing f, int0nf(x) dx ≤ ∑i=1n f(i) ≤ int1n+1f(x) dx

3. From loops to sums (non-recursive algorithms)

Recipe (Levitin §2.3):

  1. Pick the input size n.
  2. Find the basic operation (usually in the innermost loop).
  3. Ask whether the count depends only on n, or also on the particular input. If it varies, analyze worst, best (and average) cases separately.
  4. Write the count as a sum, one ∑ per loop, using the loop's exact bounds.
  5. Simplify with the formulas above; state the closed form, then the order of growth.

Example — "are all elements distinct?" by brute force.

for i ← 0 to n − 2 do for j ← i + 1 to n − 1 do if A[i] = A[j] then return false

Worst case (all distinct, or the only duplicate pair is the last one checked):

Cworst(n) = ∑i=0n−2 ∑j=i+1n−1 1 = ∑i=0n−2(n − 1 − i) = (n − 1)n/2 ∈ Θ(n2)

4. From recursion to recurrences

Recipe (Levitin §2.4): size → basic operation → does the count vary by input? → set up a recurrence with an initial condition → solve it (backward substitution, Master Theorem, or characteristic equation) → order of growth.

4.1 Backward substitution, step by step

  1. Write the recurrence for n, then for n − 1 (or n/2), and substitute it back in.
  2. Repeat two or three times until you see the pattern after i substitutions.
  3. Write that general form with i.
  4. Choose i so the argument hits the initial condition (for example i = n − 1, or i = k when n = 2k).
  5. Simplify with the sum formulas, then check the result on a small n.

Worked example A — Tower of Hanoi: M(n) = 2M(n − 1) + 1, M(1) = 1

M(n) = 2M(n − 1) + 1
= 2[2M(n − 2) + 1] + 1 = 22M(n − 2) + 2 + 1
= 23M(n − 3) + 22 + 2 + 1
= 2iM(n − i) + 2i−1 + … + 2 + 1 = 2iM(n − i) + 2i − 1

Set i = n − 1: M(n) = 2n−1·1 + 2n−1 − 1 = 2n − 1 ∈ Θ(2n). Check: M(3) = 2·3 + 1 = 7 = 23 − 1 ✔.

Worked example B — counting binary digits: A(n) = A(⌊n/2⌋) + 1, A(1) = 0

Solve for n = 2k (the smoothness rule says the order of growth carries over to all n):

A(2k) = A(2k−1) + 1 = A(2k−2) + 2 = … = A(2k−i) + i

Set i = k: A(2k) = A(1) + k = k, so A(n) = log2 n ∈ Θ(log n). (The exact answer for every n is ⌊log2 n⌋ additions; the bit count is that plus one.)

Worked example C — the exam favorite: T(n) = T(n/2) + log2 n, T(1) = 0

This is not covered by the basic Master Theorem, because f(n) = log n is not of the form nd. Backward substitution handles it. Let n = 2k, so log2 n = k:

T(2k) = T(2k−1) + k
= T(2k−2) + (k − 1) + k
= T(2k−i) + (k − i + 1) + … + (k − 1) + k

Set i = k: T(2k) = T(1) + 1 + 2 + … + k = k(k + 1)/2. Back in terms of n: T(n) = log2 n (log2 n + 1)/2 ∈ Θ(log2 n). Check: T(4) = T(2) + 2 = (T(1) + 1) + 2 = 3 and 2·3/2 = 3 ✔.

Worked example D — x(n) = x(n − 1) + n, x(0) = 0

x(n) = x(n − 2) + (n − 1) + n = … = x(0) + 1 + 2 + … + n = n(n + 1)/2 ∈ Θ(n2).

4.2 Three general solutions (Levitin Appendix B, restated)

Recurrence typeRecurrenceUnrolled solution
Decrease-by-oneT(n) = T(n − 1) + f(n)T(n) = T(0) + ∑j=1n f(j)
Decrease-by-a-constant-factorT(n) = T(n/b) + f(n), n = bkT(bk) = T(1) + ∑j=1k f(bj)
Divide-and-conquerT(n) = aT(n/b) + f(n), n = bkT(n) = nlogb a[T(1) + ∑j=1k f(bj)/aj]

Plug f(n) = log2 n with b = 2 into the second row: ∑j=1k j = k(k + 1)/2 — example C again.

5. The Master Theorem

For T(n) = a T(n/b) + f(n) with a ≥ 1, b ≥ 2 and f(n) ∈ Θ(nd), d ≥ 0:

CaseConditionSolutionWhere the work is
1a < bdT(n) ∈ Θ(nd)at the root (the combine step dominates)
2a = bdT(n) ∈ Θ(nd log n)spread evenly over logb n levels
3a > bdT(n) ∈ Θ(nlogb a)at the leaves (there are nlogb a of them)

The same conclusions hold with O and Ω in place of Θ.

Worked examples

AlgorithmRecurrencea, b, dCompare a with bdResult
Binary searchT(n) = T(n/2) + 11, 2, 01 = 20Θ(log n)
MergesortT(n) = 2T(n/2) + n2, 2, 12 = 21Θ(n log n)
Sum of an array by halvesT(n) = 2T(n/2) + 12, 2, 02 > 20Θ(nlog2 2) = Θ(n)
Karatsuba multiplicationT(n) = 3T(n/2) + n3, 2, 13 > 21Θ(nlog2 3) ≈ Θ(n1.585)
StrassenT(n) = 7T(n/2) + n27, 2, 27 > 22Θ(nlog2 7) ≈ Θ(n2.807)
Four half-size productsT(n) = 4T(n/2) + n24, 2, 24 = 22Θ(n2 log n)
Unbalanced combineT(n) = 2T(n/2) + n22, 2, 22 < 22Θ(n2)
Ternary splitT(n) = 3T(n/3) + n3, 3, 13 = 31Θ(n log n)

When it does not apply: f(n) not polynomial (like log n in example C), subproblems of unequal size (like quicksort's worst case T(n) = T(n − 1) + n), or a subtractive recurrence (T(n − 1)). Use substitution instead.

Recursion-tree picture

Draw the calls level by level. Level i has ai nodes, each doing f(n/bi) work, and there are logb n levels. Add the levels. If the level sums shrink geometrically, the root wins (case 1). If they are equal, multiply by the number of levels (case 2). If they grow, the leaves win (case 3).

6. Linear recurrences with constant coefficients — the characteristic equation

For the homogeneous second-order recurrence

a x(n) + b x(n − 1) + c x(n − 2) = 0

write the characteristic equation ar2 + br + c = 0 and find its roots r1, r2:

RootsGeneral solution
real and distinctx(n) = αr1n + βr2n
real and equal (r1 = r2 = r)x(n) = αrn + βnrn
complex u±ivx(n) = γn[α cos(nθ) + β sin(nθ)], γ = √(u2 + v2), θ = arctan(v/u)

Then use the two initial conditions to find α and β.

Worked example E — x(n) = 5x(n − 1) − 6x(n − 2), x(0) = 1, x(1) = 4. Characteristic equation: r2 − 5r + 6 = 0, roots r1 = 2, r2 = 3. So x(n) = α2n + β3n. From x(0): α + β = 1. From x(1): 2α + 3β = 4. Hence β = 2, α = −1 and x(n) = 2·3n − 2n. Check: x(2) = 5·4 − 6·1 = 14 = 18 − 4 ✔.

Worked example F — Fibonacci, F(n) = F(n − 1) + F(n − 2), F(0) = 0, F(1) = 1. r2 − r − 1 = 0 gives φ = (1 + √5)/2 ≈ 1.618 and φ̂ = (1 − √5)/2 ≈ −0.618, so F(n) = 1/√5(φn − φ̂n) and F(n) ∈ Θ(φn). Because |φ̂| < 1, F(n) is φn/√5 rounded to the nearest integer.

Inhomogeneous with a constant: for x(n) = r x(n − 1) + c with r ≠ 1, add the constant particular solution p = c/(1 − r). Tower of Hanoi: M(n) = 2M(n − 1) + 1 gives p = −1, so M(n) = α2n − 1, and M(1) = 1 forces α = 1: M(n) = 2n − 1, as in example A.

🧭 Cheat sheet 3 of 5

Design Strategies

View as Markdown on GitHub ↗

Use it when you face a new problem and don't know where to start. Follow the flowchart, then copy the template for the strategy it points to. Every template below is real Forge Pseudocode: it runs in the Practice Arena and was checked by tools/check-pseudocode-snippets.mjs.

Acronyms on this page: Dynamic Programming (DP), Traveling Salesman Problem (TSP), Minimum Spanning Tree (MST), Longest Common Subsequence (LCS), Depth-First Search (DFS), Breadth-First Search (BFS), Adelson-Velsky–Landis (AVL) tree, Binary Search Tree (BST), Nondeterministic Polynomial time (NP).


1. The decision flowchart

Start: describe the input, the output and how big n really is — then write the brute force first (your baseline and test oracle).
1Is the brute force fast enough for the real n?yes →Ship it — keep the brute force as a test
2Are you building an optimal answer piece by piece, and is one local choice provably safe?yes →Greedy
3Does one smaller instance of the same problem give the answer (shrink by 1, by half, or by a varying amount)?yes →Decrease-and-conquer
4Does it split into several smaller instances of the same problem?yes →independent parts → Divide-and-conqueroverlapping parts → Dynamic programming
5Would another form make it easy — sorted, a heap, a balanced tree, a different problem?yes →Transform-and-conquer
6Many queries, or a small key range — can memory buy time?yes →Space-time trade-off
7Optimization with a feasible start and a move that improves it?yes →Iterative improvement
Probably NP-hard. Exact: backtracking, branch-and-bound. Fast: approximation algorithms with a proven ratio.

Three questions that settle most cases

  1. What is the smallest version of this problem, and how does the answer for a bigger one reuse it? (decrease, divide, DP)
  2. If I take the obvious best-looking step, can I prove I never regret it? (greedy — prove it with an exchange argument, or find a counterexample on a tiny input)
  3. Would the problem be trivial if the data were sorted / in a heap / in a hash table? (transform, space-time)

2. The strategies at a glance

StrategyCore moveTypical recurrence or countSignature problems
Brute forceDo what the definition saysa sum over all pairs or positionsselection sort, string matching, closest pair, element uniqueness
Exhaustive searchGenerate every candidate, keep the best2n subsets or n! permutationsTSP, knapsack, assignment, subset-sum
Decrease-and-conquerSolve one smaller instance, extend itT(n) = T(n − 1) + f(n) or T(n/b) + f(n)insertion sort, topological sort, binary search, Euclid, quickselect
Divide-and-conquerSolve several independent smaller instances, combineT(n) = aT(n/b) + f(n)mergesort, quicksort, Karatsuba, Strassen, closest pair
Transform-and-conquerChange the representation or the problemcost of the transform + cost of the easy versionpresorting, Gaussian elimination, heaps, AVL and 2-3 trees, Horner, reductions
Space-time trade-offPrecompute a table or indexextra memory Θ(range) or Θ(n)counting sort, Horspool, Boyer–Moore, hashing, B-trees
Dynamic programmingSolve each overlapping subproblem once, in a tabletable size × work per cellcoin-row, change-making, knapsack, LCS, optimal BST, Warshall, Floyd
GreedyTake the locally best piece; never undooften a sort plus a heap: Θ(n log n)Prim, Kruskal, Dijkstra, Huffman, activity selection
Iterative improvementStart feasible; improve until no move helpsnumber of improving steps × cost per stepsimplex, maximum flow, bipartite matching, stable marriage
Backtracking / branch-and-boundBuild partial solutions; abandon hopeless ones earlyexponential worst case, much less in practicen-queens, subset-sum, Hamiltonian circuit, knapsack, assignment
ApproximationAccept a provably near-optimal answer quicklypolynomialtwice-around-the-tree TSP, greedy knapsack, first-fit decreasing bin packing

3. Templates in Forge Pseudocode

Each template is the smallest real algorithm that shows the strategy's shape. Keep the shape, swap the details.

Brute force — check every pair

ALGORITHM UniqueElements(A[0..n-1]) // Brute force: compare every pair exactly once for i ← 0 to n - 2 do for j ← i + 1 to n - 1 do if A[i] = A[j] then return false return true

Cost: ∑i=0n−2(n − 1 − i) = n(n − 1)/2 comparisons in the worst case.

Exhaustive search — try every subset

ALGORITHM BestSubsetValue(W[0..n-1], V[0..n-1], cap) // Exhaustive search: each number mask in 0 .. 2^n - 1 encodes one subset of the items best ← 0 for mask ← 0 to 2^n - 1 do weight ← 0 value ← 0 m ← mask for i ← 0 to n - 1 do if m mod 2 = 1 then weight ← weight + W[i] value ← value + V[i] m ← m div 2 if weight ≤ cap and value > best then best ← value return best

Cost: Θ(n2n). Fine for n ≤ 20, hopeless for n = 60.

Decrease-and-conquer — by one (insertion sort)

ALGORITHM InsertionSort(A[0..n-1]) // Decrease by one: A[0..i-1] is already sorted; insert A[i] into it for i ← 1 to n - 1 do v ← A[i] j ← i - 1 while j ≥ 0 and A[j] > v do A[j + 1] ← A[j] j ← j - 1 A[j + 1] ← v return A
ALGORITHM BinarySearch(A[0..n-1], K) // Decrease by half: each comparison throws away half of the remaining range l ← 0 r ← n - 1 while l ≤ r do m ← ⌊(l + r) / 2⌋ if K = A[m] then return m else if K < A[m] then r ← m - 1 else l ← m + 1 return -1

Decrease-and-conquer — variable size (Euclid)

ALGORITHM Euclid(m, n) // Variable-size decrease: gcd(m, n) = gcd(n, m mod n) while n ≠ 0 do r ← m mod n m ← n n ← r return m

Divide-and-conquer — mergesort

ALGORITHM Mergesort(A[0..n-1]) // Divide: split into halves. Conquer: sort each. Combine: merge. if n > 1 then B ← A[0..⌊n/2⌋ - 1] C ← A[⌊n/2⌋..n - 1] Mergesort(B) Mergesort(C) Merge(B, C, A) return A ALGORITHM Merge(B, C, A) // Merges sorted lists B and C into A p ← length(B) q ← length(C) i ← 0 j ← 0 k ← 0 while i < p and j < q do if B[i] ≤ C[j] then A[k] ← B[i] i ← i + 1 else A[k] ← C[j] j ← j + 1 k ← k + 1 while i < p do A[k] ← B[i] i ← i + 1 k ← k + 1 while j < q do A[k] ← C[j] j ← j + 1 k ← k + 1

Recurrence: C(n) = 2C(n/2) + (n − 1) comparisons in the worst case, so Θ(n log n) by the Master Theorem.

Transform-and-conquer — presort, then scan

ALGORITHM PresortUnique(A[0..n-1]) // Transform: after sorting, equal elements sit next to each other B ← sorted(A) for i ← 0 to n - 2 do if B[i] = B[i + 1] then return false return true

Cost: Θ(n log n) for the sort + Θ(n) for the scan, instead of Θ(n2).

Space-time trade-off — distribution counting

ALGORITHM CountingSort(A[0..n-1], l, u) // Space for time: count each value in the small range l..u, then place keys directly D ← array(u - l + 1, 0) for i ← 0 to n - 1 do D[A[i] - l] ← D[A[i] - l] + 1 for j ← 1 to u - l do D[j] ← D[j - 1] + D[j] S ← array(n, 0) for i ← n - 1 downto 0 do j ← A[i] - l S[D[j] - 1] ← A[i] D[j] ← D[j] - 1 return S

Cost: Θ(n + (u − l)), with no key comparisons at all. Stable, because the last loop runs right to left.

Dynamic programming — coin-row

ALGORITHM CoinRow(C[1..n]) // F[i] = best total using only the first i coins (no two adjacent) F ← array(n + 1, 0) F[1] ← C[1] for i ← 2 to n do F[i] ← max(C[i] + F[i - 2], F[i - 1]) return F[n]

The recipe: (1) define what a table cell means in words, (2) write the recurrence, (3) find the base cases, (4) fill the table in an order where every cell's inputs are ready, (5) trace back if you need the choices.

Greedy — activity selection

ALGORITHM MaxActivities(S[0..n-1], E[0..n-1]) // Greedy: activities are already sorted by finish time; // always take the next one that starts after the last chosen one ends count ← 1 lastEnd ← E[0] for i ← 1 to n - 1 do if S[i] ≥ lastEnd then count ← count + 1 lastEnd ← E[i] return count

Why it is safe: the activity that ends first leaves the most room for the rest (an exchange argument). With the sort, the cost is Θ(n log n).

Iterative improvement — augmenting paths (bipartite matching)

ALGORITHM MaxMatching(adj, m) // adj[u] = right-side vertices that left vertex u may be matched to; m = size of the right side // Start with the empty matching (feasible) and grow it along augmenting paths matchR ← array(m, -1) size ← 0 for u ← 0 to length(adj) - 1 do seen ← array(m, false) if Augment(u, adj, matchR, seen) then size ← size + 1 return size ALGORITHM Augment(u, adj, matchR, seen) // Finds an alternating path from u to a free right vertex and flips it for each v in adj[u] do if not seen[v] then seen[v] ← true if matchR[v] = -1 or Augment(matchR[v], adj, matchR, seen) then matchR[v] ← u return true return false

Each successful augmentation adds one matched pair; when none exists, the matching is maximum (Levitin §10.3).

Backtracking — n-queens

ALGORITHM CountQueens(n) // Place one queen per row; back up as soon as a placement is attacked col ← array(n, 0) return Place(0, n, col) ALGORITHM Place(r, n, col) if r = n then return 1 total ← 0 for c ← 0 to n - 1 do ok ← true for k ← 0 to r - 1 do if col[k] = c or |col[k] - c| = r - k then ok ← false if ok then col[r] ← c total ← total + Place(r + 1, n, col) return total

Branch-and-bound — knapsack with an optimistic bound

ALGORITHM KnapsackBB(W[0..n-1], V[0..n-1], cap) // Items are pre-sorted by value/weight ratio, best first best ← [0] Explore(0, 0, 0, W, V, cap, best) return best[0] ALGORITHM Explore(i, w, v, W, V, cap, best) if v > best[0] then best[0] ← v if i = length(W) then return 0 // Bound: fill the remaining capacity at the best remaining ratio (never an underestimate) ub ← v + (cap - w) * V[i] / W[i] if ub ≤ best[0] then return 0 if w + W[i] ≤ cap then Explore(i + 1, w + W[i], v + V[i], W, V, cap, best) Explore(i + 1, w, v, W, V, cap, best) return 0

The bound prunes every branch that cannot beat the best complete solution found so far (Levitin §12.2).

4. Proof tools that go with each strategy

StrategyHow you argue it is correctHow you get its cost
Brute force, iterative loopsloop invariant (initialization, maintenance, termination)sums
Decrease / divide-and-conquerinduction on nrecurrences, Master Theorem
Dynamic programmingthe recurrence is correct (optimal substructure) + fill ordertable size × work per cell
Greedyexchange argument, or "greedy stays ahead"usually sort + heap operations
Iterative improvementa certificate of optimality (min cut, no augmenting path)number of iterations × cost each
Backtracking / branch-and-boundevery pruned branch provably contains no better solutionworst case exponential; measure in practice
⏱️ Cheat sheet 4 of 5

Complexity Table

View as Markdown on GitHub ↗

Use it when you need the running time of an algorithm at a glance, or want to compare two algorithms for the same job. Chapters 1–12 follow Levitin; Chapters 13–17 are the Beyond-the-textbook lessons.

How to read it. Times count the basic operation named in the lesson (key comparisons for sorting and searching, multiplications for arithmetic). "Space" is the extra memory beyond the input. In graph rows, V and E are the numbers of vertices and edges. "Stable" means equal keys keep their input order; "in place" means Θ(1) extra array memory (a recursion stack may still be used). A dash means the idea does not apply.

Acronyms: Greatest Common Divisor (GCD), Depth-First Search (DFS), Breadth-First Search (BFS), Traveling Salesman Problem (TSP), Binary Search Tree (BST), Adelson-Velsky–Landis tree (AVL), Knuth–Morris–Pratt (KMP), Dynamic Programming (DP), Longest Common Subsequence (LCS), Minimum Spanning Tree (MST), Directed Acyclic Graph (DAG), Strongly Connected Components (SCC), Longest Increasing Subsequence (LIS), Least Recently Used (LRU), input/output (I/O), Least Common Multiple (LCM), Boolean satisfiability (SAT), Nondeterministic Polynomial time (NP), First-Fit Decreasing (FFD).


Chapters 1–2 · Introduction and the analysis framework

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Euclid's GCD1Θ(1)Θ(log n)Θ(log n)Θ(1)—gcd(m, n) = gcd(n, m mod n); worst case on consecutive Fibonacci numbers
Consecutive-integer GCD check1Θ(1)—Θ(min(m, n))Θ(1)—try t = min(m, n), min − 1, … until t divides both
Sieve of Eratosthenes1Θ(n log log n)Θ(n log log n)Θ(n log log n)Θ(n)—cross out multiples of each prime p, starting at p²
Sequential search2Θ(1)(n + 1)/2 if found, Θ(n)n comparisons, Θ(n)Θ(1)—scan until found; a sentinel removes the bounds check
Largest element2n − 1n − 1n − 1Θ(1)—keep the best so far; input-insensitive
Element uniqueness (brute force)2Θ(1)—n(n − 1)/2, Θ(n²)Θ(1)—compare every pair once
Matrix multiplication (definition)2n³n³n³ multiplicationsΘ(n²) for the result—each of n² entries is a length-n dot product
Binary digit count2Θ(log n)Θ(log n)⌊log₂ n⌋ + 1 digitsΘ(1)—halve until 1; the recursive version adds Θ(log n) stack
Factorial (recursive)2n multiplicationsnnΘ(n) stack—M(n) = M(n − 1) + 1
Tower of Hanoi22ⁿ − 1 moves2ⁿ − 12ⁿ − 1Θ(n) stack—move n − 1 aside, move the largest, move n − 1 back
Fibonacci, naive recursion2Θ(φⁿ)Θ(φⁿ)Θ(φⁿ) callsΘ(n) stack—the same subproblems recomputed exponentially often
Fibonacci, iterative2Θ(n)Θ(n)Θ(n)Θ(1)—keep only the last two values
Fibonacci, matrix power2Θ(log n)Θ(log n)Θ(log n) matrix productsΘ(1)—power of [[1, 1], [1, 0]] by repeated squaring
AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Selection sort3n(n − 1)/2n(n − 1)/2n(n − 1)/2 comparisonsΘ(1)not stable · in placeonly n − 1 swaps — good when writes are expensive
Bubble sort3Θ(n²) (Θ(n) with early exit)Θ(n²)n(n − 1)/2 comparisonsΘ(1)stable · in placeadjacent swaps bubble the maximum to the end
Brute-force string matching3Θ(m)Θ(n) on random textm(n − m + 1), Θ(nm)Θ(1)—try every alignment of the pattern (length m) in the text (length n)
Closest pair (brute force)3Θ(n²)Θ(n²)Θ(n²)Θ(1)—all n(n − 1)/2 pairs; compare squared distances
Convex hull (brute force)3Θ(n³)Θ(n³)Θ(n³)Θ(n)—a pair is a hull edge if every other point is on one side
TSP (exhaustive search)3Θ(n!)Θ(n!)(n − 1)!/2 toursΘ(n)—fix the start city; every tour and its reverse count once
Knapsack (exhaustive search)3Θ(n·2ⁿ)Θ(n·2ⁿ)Θ(n·2ⁿ)Θ(n)—every subset of items
Assignment (exhaustive search)3Θ(n·n!)Θ(n·n!)Θ(n·n!)Θ(n)—every permutation of jobs
DFS / BFS, adjacency matrix3Θ(V²)Θ(V²)Θ(V²)Θ(V)—scanning a row costs V even for few neighbors
DFS / BFS, adjacency lists3Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—DFS uses a stack (recursion), BFS a queue

Chapter 4 · Decrease-and-conquer

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Insertion sort4n − 1≈ n²/4n(n − 1)/2 comparisonsΘ(1)stable · in placeinsert A[i] into the sorted A[0..i − 1]; great on almost-sorted data
Topological sort (DFS or source removal)4Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—reverse DFS finishing order, or repeatedly delete a source
Permutations (Johnson–Trotter, lexicographic)4Θ(n!)Θ(n!)Θ(n!)Θ(n)—each new permutation is one adjacent swap away (Johnson–Trotter)
Subsets (binary counting, Gray code)4Θ(2ⁿ)Θ(2ⁿ)Θ(2ⁿ)Θ(n)—Gray code changes exactly one element per step
Binary search41≈ log₂ n⌊log₂ n⌋ + 1 comparisonsΘ(1)—discard half of the sorted range each step
Fake-coin problem4Θ(log n)Θ(log n)⌈log₃ n⌉ weighings (3 piles)Θ(1)—split into piles and weigh; the light pile holds the fake
Russian peasant multiplication4Θ(log n)Θ(log n)Θ(log n)Θ(1)—halve n, double m, add m when n is odd
Josephus problem4Θ(log n)Θ(log n)Θ(log n)Θ(1)—J(n) = one-bit cyclic left shift of n in binary
Quickselect (Lomuto)4Θ(n)Θ(n)Θ(n²)Θ(1)—partition, then recurse into only the side holding the k-th element
Interpolation search4Θ(1)Θ(log log n) on uniform keysΘ(n)Θ(1)—guess the position from the key's value
BST search / insert4Θ(1)Θ(log n) (random insertions)Θ(n)Θ(1)—go left or right at each node; degenerates into a list

Chapter 5 · Divide-and-conquer

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Mergesort5Θ(n log n)Θ(n log n)n log₂ n − n + 1 comparisonsΘ(n)stable · not in placesort halves, merge in linear time
Quicksort5Θ(n log n)≈ 1.39 n log₂ nΘ(n²)Θ(log n) stack (average)not stable · in placepartition around a pivot; recurse on both sides
Binary tree traversals (pre/in/post)5Θ(n)Θ(n)Θ(n)Θ(height) stack—visit root, left subtree, right subtree in some order
Tree height, leaf count5Θ(n)Θ(n)Θ(n)Θ(height) stack—answer for the root from the answers for the subtrees
Karatsuba multiplication5Θ(n^1.585)Θ(n^1.585)Θ(n^1.585) digit multiplicationsΘ(n)—three half-size products instead of four
Strassen matrix multiplication5Θ(n^2.807)Θ(n^2.807)Θ(n^2.807)Θ(n²)—seven half-size products instead of eight
Closest pair (divide-and-conquer)5Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—presort by x and y; only a narrow strip needs checking
QuickHull5Θ(n log n)Θ(n log n) typicalΘ(n²)Θ(n)—the farthest point from a line splits the problem in two

Chapter 6 · Transform-and-conquer

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Presorting: uniqueness, mode6Θ(n log n)Θ(n log n)Θ(n log n)depends on the sort—after sorting, equal values are neighbors
Gaussian elimination6Θ(n³)Θ(n³)≈ n³/3 multiplicationsΘ(1) extra—reduce to upper-triangular form, back-substitute
AVL tree search / insert / delete6Θ(log n)Θ(log n)Θ(log n)Θ(n) nodes—rotations keep the two subtree heights within 1
2-3 tree search / insert6Θ(log n)Θ(log n)Θ(log n)Θ(n) nodes—all leaves on one level; full nodes split upward
Heap: bottom-up construction6Θ(n)Θ(n)< 2n comparisonsΘ(1)in placesift down from the last parent to the root
Heap: insert, delete the root6Θ(1)Θ(log n)Θ(log n)Θ(1)in placesift up / sift down along one path
Heapsort6Θ(n log n)Θ(n log n)Θ(n log n)Θ(1)not stable · in placebuild a heap, then delete the maximum n − 1 times
Horner's rule6nnn multiplications and n additionsΘ(1)—p(x) = (…(aₙx + aₙ₋₁)x + …)x + a₀
Binary exponentiation (left-to-right, right-to-left)6Θ(log n)Θ(log n)≤ 2⌊log₂ n⌋ multiplicationsΘ(1)—square for every bit of n, multiply for every 1 bit
LCM via GCD6Θ(1)Θ(log n)Θ(log n)Θ(1)—lcm(m, n) = m·n / gcd(m, n) (problem reduction)

Chapter 7 · Space-time trade-offs

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Comparison counting sort7n(n − 1)/2n(n − 1)/2n(n − 1)/2 comparisonsΘ(n)not in placean element's position = how many elements are smaller
Distribution counting sort7Θ(n + r)Θ(n + r)Θ(n + r)Θ(n + r)stable · not in placecount each value in a range of size r, prefix-sum, place
Radix sort (least significant digit first)7Θ(d(n + r))Θ(d(n + r))Θ(d(n + r))Θ(n + r)stabled passes of a stable sort, one per digit
Bucket sort7Θ(n)Θ(n) on uniform keysΘ(n²)Θ(n)stable (with insertion sort)spread keys into buckets, sort each bucket
Horspool string matching7Θ(n/m)Θ(n) on random textΘ(nm)Θ(alphabet)—shift by the table entry for the text character under the pattern's last position
Boyer–Moore string matching7Θ(n/m)often sublinearΘ(nm) in simple versionsΘ(m + alphabet)—bad-symbol and good-suffix shifts, take the larger
KMP string matching7Θ(n + m)Θ(n + m)Θ(n + m)Θ(m)—the prefix function says how far to fall back without rereading the text
Hashing, separate chaining7Θ(1)≈ 1 + α/2 probes (successful)Θ(n)Θ(n + m)—load factor α = n/m keys per cell
Hashing, linear probing7Θ(1)≈ ½(1 + 1/(1 − α)) probes (successful)Θ(n)Θ(m)—clusters form as α approaches 1
B-tree search / insert7Θ(log n)Θ(log n)Θ(log n): about log base m/2 of n disk readsΘ(n)—wide nodes (order m) keep the tree very short

Chapter 8 · Dynamic programming

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Coin-row problem8Θ(n)Θ(n)Θ(n)Θ(n), or Θ(1) with two variables—F(i) = max(cᵢ + F(i − 2), F(i − 1))
Change-making (DP)8Θ(nm)Θ(nm)Θ(nm)Θ(n)—amount n, m denominations: F(n) = 1 + min over coins of F(n − dⱼ)
Robot coin collection8Θ(nm)Θ(nm)Θ(nm)Θ(nm)—F(i, j) = max(F(i − 1, j), F(i, j − 1)) + coin(i, j)
0/1 knapsack (bottom-up)8Θ(nW)Θ(nW)Θ(nW)Θ(nW)—pseudo-polynomial: W is a value, not a size
Knapsack memory function8fewer cellsfewer cellsΘ(nW)Θ(nW)—top-down recursion, computing each needed cell once
Binomial coefficient8Θ(nk)Θ(nk)Θ(nk)Θ(k) possible—Pascal's rule C(n, k) = C(n − 1, k − 1) + C(n − 1, k)
LCS, edit distance8Θ(mn)Θ(mn)Θ(mn)Θ(mn), Θ(min) for the value only—a 2-D table over prefixes of both strings
Optimal BST8Θ(n³)Θ(n³)Θ(n³)Θ(n²)—try every root for every range; Θ(n²) with Knuth's speedup
Warshall (transitive closure)8Θ(n³)Θ(n³)Θ(n³)Θ(n²)—allow intermediate vertices 1..k, one k at a time
Floyd (all-pairs shortest paths)8Θ(n³)Θ(n³)Θ(n³)Θ(n²)—D[i, j] ← min(D[i, j], D[i, k] + D[k, j])

Chapter 9 · Greedy technique

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Prim's MST, unordered array9Θ(V²)Θ(V²)Θ(V²)Θ(V)—grow one tree by its cheapest outgoing edge; good for dense graphs
Prim's MST, binary heap9O(E log V)O(E log V)O(E log V)Θ(V)—same idea with a priority queue
Kruskal's MST9O(E log E)O(E log E)O(E log E)Θ(V + E)—sort edges; add each one that joins two different trees (union–find)
Union–find, union by size + path compression9Θ(1)nearly Θ(1) amortizedO(log n) for a single findΘ(n)—shallow trees; flatten them while searching
Dijkstra, unordered array9Θ(V²)Θ(V²)Θ(V²)Θ(V)—finalize the closest unfinished vertex; non-negative weights only
Dijkstra, binary heap9O(E log V)O(E log V)O(E log V)Θ(V)—same with a priority queue
Huffman coding9Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—merge the two lightest trees, repeat
Greedy change-making9Θ(m)Θ(m)Θ(m)Θ(1)—largest coin first; optimal only for canonical coin systems
Activity selection9Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—sort by finish time, take the earliest-finishing compatible one
Fractional knapsack9Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—best value per weight first; split the last item

Chapter 10 · Iterative improvement

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Simplex method10—fast in practice (polynomially many pivots typical)exponential (Klee–Minty examples)Θ(mn) tableau—walk from vertex to adjacent better vertex
Maximum flow, shortest augmenting path10——O(V E²)Θ(V + E)—augment along the shortest path in the residual network (BFS)
Maximum bipartite matching (augmenting paths)10——O(V E)Θ(V)—flip an alternating path that starts and ends at free vertices
Stable marriage (Gale–Shapley)10Θ(n) proposals—Θ(n²) proposalsΘ(n²) preferences—free men propose in order; women trade up

Chapters 11–12 · Limits, and coping with them

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Any comparison sort (lower bound)11—≥ log₂ n!≥ ⌈log₂ n!⌉ ≈ n log₂ n comparisons——a decision tree needs n! leaves
Searching a sorted array (lower bound)11——≥ ⌈log₂(n + 1)⌉ comparisons——a ternary decision tree with 2n + 1 leaves
SAT: verify a certificate vs. brute force11——verify Θ(formula size); brute force Θ(2ⁿ · size)——NP = quick to check, not necessarily quick to find
Backtracking (n-queens, subset-sum, Hamiltonian circuit)12smallusually far less than the full treeexponentialΘ(n) stack—extend a partial solution; back up when it can't be completed
Branch-and-bound (assignment, knapsack, TSP)12smalldepends on the boundexponentialup to exponential (best-first)—prune nodes whose bound can't beat the best solution so far
Nearest-neighbor TSP12Θ(n²)Θ(n²)Θ(n²)Θ(n)—go to the closest unvisited city; accuracy ratio unbounded
Twice-around-the-tree TSP12Θ(n²)Θ(n²)Θ(n²) with PrimΘ(n)—MST walk with shortcuts; ≤ 2 × optimal on Euclidean instances
Christofides TSP12Θ(n³)Θ(n³)Θ(n³)Θ(n²)—MST + minimum-weight matching on odd vertices; ≤ 1.5 × optimal (metric)
Greedy knapsack approximation (enhanced)12Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—best ratio first, compared with the single most valuable item: ≥ ½ optimal
First-fit / first-fit decreasing bin packing12Θ(n²) simpleΘ(n²)Θ(n²) (Θ(n log n) with a tree)Θ(n)—FFD uses at most about 11/9 × the optimal number of bins (plus a constant)
Bisection method12——⌈log₂((b − a)/ε)⌉ iterationsΘ(1)—halve an interval where the sign changes; always converges
Newton's method12—quadratic convergence near a simple rootmay divergeΘ(1)—xₙ₊₁ = xₙ − f(xₙ)/f′(xₙ)

Chapters 13–17 · Beyond the textbook

AlgorithmChBestAverageWorstSpaceStable / in placeKey idea
Dynamic array append (doubling)13Θ(1)Θ(1) amortizedΘ(n) for one resizeΘ(n)—double the capacity when full; total copying < 2n
Fenwick tree (binary indexed tree)13Θ(log n)Θ(log n)Θ(log n) per update or prefix queryΘ(n)—index i covers a range of length lowbit(i)
Segment tree13Θ(log n)Θ(log n)Θ(log n) per query/update; Θ(n) buildΘ(n) (about 4n)—each node stores the answer for one segment
Trie13Θ(L)Θ(L)Θ(L) per word of length LΘ(total characters)—one edge per character; shared prefixes share nodes
Skip list13Θ(1)Θ(log n) expectedΘ(n)Θ(n) expected—random express lanes over a sorted linked list
LRU cache (hash map + linked list)13Θ(1)Θ(1)Θ(1) expectedΘ(capacity)—the map finds the node; the list keeps recency order
Red-black tree13Θ(log n)Θ(log n)Θ(log n)Θ(n)—colors guarantee height ≤ 2 log₂(n + 1)
Bellman–Ford14Θ(E) (early stop)Θ(VE)Θ(VE)Θ(V)—relax every edge V − 1 times; one more round detects a negative cycle
A* search14depends on the heuristic—O(E log V) with a consistent heuristicΘ(V)—Dijkstra ordered by g + h, where h never overestimates
0-1 BFS14Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—a deque: weight-0 edges to the front, weight-1 to the back
SCC (Kosaraju, Tarjan)14Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—two DFS passes (Kosaraju) or one pass with low-links (Tarjan)
Bridges and articulation points14Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—low-link values from one DFS
DAG shortest / longest path14Θ(V + E)Θ(V + E)Θ(V + E)Θ(V)—relax edges in topological order
Two pointers, sliding window15Θ(n)Θ(n)Θ(n)Θ(1) or Θ(alphabet)—each pointer only moves forward: at most 2n steps
Monotonic stack / deque15Θ(n)Θ(n)Θ(n)Θ(n)—every element is pushed and popped at most once
Binary search on the answer15Θ(n log R)Θ(n log R)Θ(n log R)Θ(1)—R = range of candidate answers; a feasibility check costs n
Kadane's maximum subarray15Θ(n)Θ(n)Θ(n)Θ(1)—best sum ending here = max(x, best ending before + x)
LIS, quadratic DP15Θ(n²)Θ(n²)Θ(n²)Θ(n)—L(i) = 1 + max L(j) over earlier smaller elements
LIS, patience sorting15Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—binary search for the pile each element joins
Matrix-chain order15Θ(n³)Θ(n³)Θ(n³)Θ(n²)—interval DP over every split point
Held–Karp TSP15Θ(n²2ⁿ)Θ(n²2ⁿ)Θ(n²2ⁿ)Θ(n2ⁿ)—DP over (set of visited cities, last city)
Merge intervals15Θ(n log n)Θ(n log n)Θ(n log n)Θ(n)—sort by start, then sweep
k-way merge / top-k with a heap15Θ(N log k)Θ(N log k)Θ(N log k)Θ(k)—a heap of size k holds one candidate per list
Randomized quicksort16Θ(n log n)≈ 1.39 n log₂ n expectedΘ(n²) (vanishingly unlikely)Θ(log n) expectednot stable · in placea random pivot makes every input "average"
Karger's min cut (one run)16Θ(n²)Θ(n²)Θ(n²)Θ(n + E)—contract random edges; succeeds with probability ≥ 2/(n(n − 1))
Miller–Rabin primality (k rounds)16O(k log³ n)O(k log³ n)O(k log³ n)Θ(1)—error probability ≤ 4⁻ᵏ
Bloom filter (k hash functions)16Θ(k)Θ(k)Θ(k) per insert or querym bits—no false negatives; false-positive rate ≈ (1 − e^(−kn/m))^k
Count-Min sketch16Θ(d)Θ(d)Θ(d) per updateΘ(d·w)—d rows of w counters; estimates only ever overcount
HyperLogLog16Θ(1)Θ(1)Θ(1) per itemm registers—standard error ≈ 1.04/√m for distinct counts
Reservoir sampling16Θ(n)Θ(n)Θ(n)Θ(k)—keep item i with probability k/i
Fisher–Yates shuffle16Θ(n)Θ(n)Θ(n)Θ(1)in placeswap A[i] with a random A[j], j ≤ i
Rabin–Karp string matching15–16Θ(n + m)Θ(n + m) expectedΘ(nm)Θ(1)—rolling hash of each window; verify on a hash match
Z-function string matching15Θ(n + m)Θ(n + m)Θ(n + m)Θ(n + m)—reuse the rightmost matched window ([l, r] box)
External merge sort17Θ((N/B) · log base M/B of (N/B))samesame I/OsΘ(M) memorystable (if runs merge stably)sort memory-sized runs, then multi-way merge
✍️ Cheat sheet 5 of 5

Pseudocode

View as Markdown on GitHub ↗

Forge Pseudocode is the Levitin-style pseudocode used in every lesson, simulation and Practice Arena problem. It is not "pretend" code: the Arena runs it, counts its operations and grades it. If you can write it on an exam, you can run it here. Every example on this page was executed by the real interpreter (docs/engine/forge-pseudo.js) with node tools/check-pseudocode-snippets.mjs.


1. The shape of an algorithm

ALGORITHM MaxElement(A[0..n-1]) // Returns the value of the largest element in A // Input: a non-empty array A of n numbers // Output: the largest value in A maxval ← A[0] for i ← 1 to n - 1 do if A[i] > maxval then maxval ← A[i] return maxval
  • A program is one or more ALGORITHM Name(parameters) blocks. The first one is the entry point (the Arena calls the name given in the problem).
  • Indentation defines blocks — 4 spaces per level, exactly like the book. end, endif, od, {, } lines are tolerated and ignored.
  • // starts a comment. The header comments (purpose, Input, Output) are a habit worth keeping.
  • A[0..n-1] in a header binds n to the array's length. A[l..r] binds l and r to the bounds the caller passed. A[1..n] gives you a 1-based view.

2. Values, assignment and arithmetic

ALGORITHM Arithmetic() a ← 7 div 2 // 3 (integer division, rounds down) b ← 7 mod 3 // 1 c ← ⌈7 / 2⌉ // 4 (7 / 2 = 3.5; ⌊ ⌋ and ⌈ ⌉ round) d ← 2^3 // 8 e ← min(∞, 5) // 5 return a + b + c + d + e
You writeMeaningPlain-keyboard alternative
x ← 5assignmentx <- 5 or x := 5
= ≠ < ≤ > ≥comparisons (= is equality, never assignment)!= <= >=
and or notlogic, short-circuit (and stops at the first false)&& || !
+ − × / div mod ^arithmetic; / is real division; div rounds down- * ** %
⌊x⌋ ⌈x⌉ |x|floor, ceiling, absolute valuefloor(x) ceil(x) abs(x)
2n n²implicit multiplication and squares are fine2 * n, n^2
∞infinity (bigger than every number)infinity
true false nullbooleans and "no value"NIL also means null
"text" 'a'strings and characters (strings can be indexed: s[0])

Several statements can share a line when separated by ; — for example i ← 0; j ← n - 1.

3. Decisions

ALGORITHM Sign(x) if x < 0 then return "negative" else if x = 0 then return "zero" else return "positive"

then is optional, and a short body can stay on the same line: if A[i] > m then m ← A[i].

4. Loops

ALGORITHM DigitSum(n) // while: test first, maybe zero iterations s ← 0 while n > 0 do s ← s + n mod 10 n ← n div 10 return s
ALGORITHM BinaryLength(n) // repeat … until: the body always runs at least once count ← 0 repeat n ← n div 2 count ← count + 1 until n = 0 return count
ALGORITHM PrintSmallPositives(A) // for each, with continue and break for each x in A do if x < 0 then continue // skip to the next x if x > 9 then break // leave the loop entirely print x
FormExample
counting upfor i ← 0 to n - 1 do (both ends included)
counting downfor i ← n - 1 downto 0 do
with a stepfor i ← 0 to n - 1 step 2 do
over elementsfor each x in A do
over pairsfor (u, w) in edges do (each element is a list like [u, w])
while / repeatwhile cond do · repeat … until cond
leave earlybreak, continue, return
ALGORITHM TotalWeight(edges) total ← 0 for (u, w) in edges do total ← total + w return total

5. Arrays, views and copies

ALGORITHM ClearMiddle(A[0..n-1]) // Passing a slice passes a VIEW: the callee writes into A itself Clear(A[1..n-2]) return A ALGORITHM Clear(B[l..r]) for i ← l to r do B[i] ← 0
ALGORITHM CopyIsSeparate(A[0..n-1]) // Assigning a slice makes a COPY: changing B leaves A alone B ← A[0..n-1] B[0] ← 99 return [A[0], B[0]]
ALGORITHM ReverseInPlace(A[0..n-1]) i ← 0 j ← n - 1 while i < j do swap A[i] and A[j] // also: A[i] ↔ A[j] i ← i + 1 j ← j - 1 return A
  • Make arrays with array(n, fill) and 2-D tables with matrix(rows, cols, fill); read cells as M[i, j] or M[i][j].
  • List literals: [1, 2, 3], []. append(L, x) adds to the end; writing one past the end also extends the array.
  • copy A[0..m-1] to B[0..m-1] copies element by element (Levitin's phrasing).
  • length(A) works on arrays and strings.
ALGORITHM Identity(n) M ← matrix(n, n, 0) for i ← 0 to n - 1 do M[i, i] ← 1 return M

6. Recursion and multiple results

ALGORITHM F(n) // Computes n! recursively if n = 0 then return 1 return F(n - 1) * n
ALGORITHM Spread(A[0..n-1]) (lo, hi) ← MinMax(A) // unpack two results return hi - lo ALGORITHM MinMax(A[0..n-1]) lo ← A[0] hi ← A[0] for i ← 1 to n - 1 do if A[i] < lo then lo ← A[i] if A[i] > hi then hi ← A[i] return (lo, hi) // returns a list [lo, hi]

7. Records (nodes)

ALGORITHM TinyTree() root ← new Node root.key ← 2 root.left ← new Node root.left.key ← 1 root.right ← null return Size(root) ALGORITHM Size(t) if t = null then return 0 return 1 + Size(t.left) + Size(t.right)

A record is created with new Name; fields appear when you assign them. A field that was never assigned is null.

8. Built-in data structures

StructureCreateOperations
stackS ← stack()push(S, x), pop(S), top(S), isEmpty(S)
queueQ ← queue()enqueue(Q, x), dequeue(Q), front(Q), isEmpty(Q)
map (dictionary)M ← map()M[k] ← v, M[k], contains(M, k), get(M, k, default), keys(M), values(M), remove(M, k)
setS ← set()add(S, x), contains(S, x), x in S
priority queueQ ← priorityQueue() (min) or maxPQ()insert(Q, item, priority), deleteMin(Q) / deleteMax(Q) (return the item), peek(Q), isEmpty(Q)
ALGORITHM MostFrequentCount(W) // map: count how often each word occurs M ← map() best ← 0 for each w in W do M[w] ← get(M, w, 0) + 1 best ← max(best, M[w]) return best
ALGORITHM BFSOrder(adj, s) // queue: breadth-first search from s; adj[v] lists v's neighbors visited ← array(length(adj), false) order ← [] Q ← queue() enqueue(Q, s) visited[s] ← true while not isEmpty(Q) do v ← dequeue(Q) append(order, v) for each w in adj[v] do if not visited[w] then visited[w] ← true enqueue(Q, w) return order
ALGORITHM Dijkstra(edges, n, s) // priority queue: shortest distances from s; edges are [u, v, weight] (undirected) adj ← array(n, null) for v ← 0 to n - 1 do adj[v] ← [] for each e in edges do append(adj[e[0]], [e[1], e[2]]) append(adj[e[1]], [e[0], e[2]]) dist ← array(n, ∞) dist[s] ← 0 Q ← priorityQueue() insert(Q, s, 0) while not isEmpty(Q) do u ← deleteMin(Q) for (v, w) in adj[u] do if dist[u] + w < dist[v] then dist[v] ← dist[u] + w insert(Q, v, dist[v]) return dist

9. More built-in functions

FunctionResult
min(a, b, …), max(…)smallest / largest argument (or of one list)
abs, sqrt, floor, ceil, round, pow(a, b)the usual math
log2(x) or lg(x), ln(x)logarithms
sum(A), sorted(A), reversed(A), reverse(A)total; sorted copy; reversed copy; reverse in place (returns A)
range(a, b)the list [a, a+1, …, b] (both ends included)
indexOf(A, x)first index of x, or −1
even(n), odd(n)parity tests
ord(c), chr(k), int(s), str(x)character codes and conversions
random(a, b)a random integer in a..b (seeded, so runs repeat exactly)
print x, ywrites a line to the Output panel
x in Lmembership test for lists, sets and map keys
ALGORITHM Builtins(A) return [sorted(A), reverse(A), sum(A), range(0, 3), indexOf(A, 1)]
x ← 3print "x is", x

(Top-level lines outside any ALGORITHM run first — handy for quick experiments.)

10. What the Arena counts

When you run pseudocode, the interpreter counts operations so you can check your analysis against reality:

CounterWhat increments it
key comparisonsa relational comparison that involves an array element, like A[j] > v
comparisonsevery relational comparison
array reads / writesevery A[i] read / every A[i] ← …
assignments, arithmetic, calls, swapswhat the names say
stepsevery executed statement (a runaway loop stops at 2,000,000)

Some problems set a budget (for example "at most n − 1 key comparisons") or a growth check (for example "must be Θ(n log n)"), so the efficiency of your solution is graded, not just its answer.

11. Friendly errors (and what they mean)

ALGORITHM OffByOne(A[0..n-1]) return A[n] // the last element is A[n - 1]
Message starts withUsual cause
"Index … is outside A[0..n−1]"an off-by-one loop bound (to n instead of to n - 1)
"I don't know the variable …"a typo, or a variable used before its first ←
"… has not been given a value yet"reading an array cell nothing wrote to
"Stopped after 2,000,000 steps"a loop whose condition never changes
"The recursion went too deep"a missing or unreachable base case