Exercises — Common complexities — O(1), O(log n), O(n), O(n log n), O(n²), O(n³), O(2ⁿ), O(n!)
Before we begin, one reminder of the ladder we are matching every answer to:
Here < means "grows strictly slower once n is large".
Figure s01 (below): the growth ladder. The horizontal axis is the input size n; the vertical axis is the number of steps , drawn on a logarithmic scale so that all eight rungs fit on one picture. Eight curves are drawn, one per class — flat , slowly-rising , straight , slightly-steeper , bending , steeper , and the two runaway curves (dashed) and (dotted). The key thing to read off the picture: each curve eventually rises above every curve below it and never dips back — that is exactly what the < chain means, and the two topmost curves ( then ) shoot off the top the fastest.

Level 1 — Recognition
(You are handed a growth pattern; name its class. No arithmetic tricks yet.)
L1.1
An algorithm always looks at exactly the first 3 elements of an array, no matter how long the array is. What is its complexity?
Recall Solution
WHAT the code does: touches a fixed number of elements — three — forever.
WHY that fixes the class: the step count never grows with n. Plotting "work vs n" gives a flat horizontal line — the flat line sitting at height 1 in figure s01.
Answer: — constant.
L1.2
Each iteration of a loop triples the value of a counter (c = c * 3) starting from 1 until it reaches n. How many iterations?
Recall Solution
WHAT: the counter goes i.e. after k steps.
WHY log: it stops at the first k with , so (using the ceiling defined above, because the iteration count must round up to a whole number). Multiplying by a constant factor each step is the signature of a logarithm (not subtracting).
WHY the base drops: — a constant multiple — and Big-O throws constants away.
Answer: .
L1.3
A function makes a take-or-skip binary choice for each of n items and explores every combination. What is its complexity?
Recall Solution
WHAT: n independent binary choices → ( twos) combinations.
WHY exponential: each new item doubles the number of paths — the steeply-rising dashed curve in figure s01 that overtakes the parabola.
Answer: .
Level 2 — Application
(Now you count steps with the summation and nesting rules.)
L2.1
for i in range(n):
for j in range(n):
do_constant_work()
Give the exact step count and its Big-O.
Recall Solution
WHAT: the inner loop runs n times, and it runs once for each of the n outer iterations.
WHY multiply: nested loops multiply because the inner work repeats fully inside every outer pass.
Answer: steps .
L2.2
for i in range(n): # loop A
work()
for j in range(n): # loop B
work()
Big-O?
Recall Solution
WHAT: two loops one after the other, not one inside the other. WHY add: sequential loops add their work: . WHY drop the 2: Big-O ignores constant factors → . Answer: .
L2.3
for i in range(n):
for j in range(i, n): # starts at i, not 0
do_constant_work()
Compute the exact number of inner calls and the Big-O.
Recall Solution
WHAT: when the outer index is i, the inner loop runs times.
WHY this sum: total .
WHY the two sums are equal: substitute . When , ; when , ; and as steps up by 1, steps down by 1. So the list of values is just the numbers written backwards:
WHY that sum equals (Gauss's pairing): write the sum forwards and backwards and add them column by column:
Every column sums to , and there are columns, so twice the sum is , giving . WHY still : expand ; the term dominates and the is a constant. Answer: calls .
Figure s02 (below): the triangle of work. A grid of shaded squares, one square per inner-loop call. Row i=0 (drawn at the top) is fully shaded across all n columns; row i=1 is one square shorter; each lower row loses one more square, so the shaded region forms a right triangle. Counting the squares in the triangle is the sum ; its area — half of the full square — is why the count is and the class is .

Level 3 — Analysis
(Messy, mixed, or deceptive code — you must reason, not pattern-match.)
L3.1
for i in range(n):
j = n
while j > 1:
j = j // 2 # floor division: keep the whole part
Big-O?
Recall Solution
WHAT the inner loop does: using floor division (//, defined at the top of this page), j steps through down to 1 — roughly halvings.
WHAT the outer loop does: runs n times, and the inner work happens fully inside each pass.
WHY multiply: nested → multiply: .
Answer: .
L3.2
i = 1
while i < n:
do_constant_work()
i = i * 2
Big-O? Then: what if the last line were i = i + 2?
Recall Solution
Case i = i*2: after iterations ; the loop stops the moment , i.e. steps (ceiling, since the count rounds up to a whole number) → .
Case i = i+2 — done carefully: after iterations the counter is (it starts at 1 and adds 2 each pass). The loop keeps going while , so the last iteration that still runs is the largest with . Solve for :
Since must be a whole number, the number of iterations is (the count of integers satisfying the strict inequality; the ceiling rounds up to include the partial step).
WHY that's : ; the ceiling changes the count by at most 1 and the is a constant factor — both dropped by Big-O.
WHY the huge gap: multiplying by a factor is the log signature; adding a constant is the linear signature. Same target n, totally different classes.
Answer: vs .
L3.3
Three separate blocks run in sequence:
- Block A: a single nested double loop →
- Block B: a merge-sort call →
- Block C: one pass over the array →
What is the total complexity?
Recall Solution
WHY add: the blocks run one after another (sequential) → add their costs:
WHY keep only : for large n, . The biggest term swallows the rest.
Answer: .
Level 4 — Synthesis
(Turn recurrences and problem descriptions into a class from scratch — see Recurrence-Relations and Master-Theorem.)
L4.1
A recursive algorithm satisfies with . Derive its Big-O by unrolling the recursion tree.
Recall Solution
WHAT the recurrence says: solve two half-sized subproblems, then do merging work.
WHY a tree: each call spawns 2 children of size ; those spawn 4 of size ; and so on.
Work per level: the top level does . The next level: two nodes each doing → total again. Every level does because the pieces shrink but there are proportionally more of them.
Number of levels — counted precisely: the sizes go . Reaching size 1 from size by repeated halving takes halvings, but we must count the levels (the rows of the tree), and there is a row before the first halving. So the levels are: level 0 (size ), level 1 (size ), …, level (size 1) — that is rows in total.
What if n is NOT a power of two? Then the halves are not exact — a real implementation splits into pieces of size and (floor and ceiling, defined at the top). The tree depth is then instead of an exact integer, and the per-level work is still at most . Rounding shifts the count by at most a constant, so the class is unchanged: . (This is exactly why the Master-Theorem states its result for general n, not just powers of two.)
Total: .
WHY the vanishes in Big-O: — the term dominates and the extra is a lower-order term, dropped.
Answer: — this is exactly Merge-Sort.
L4.2
A recurrence is with . Unroll it and give the Big-O.
Recall Solution
WHY this differs from L4.1: here the subproblem shrinks by subtracting 1 (not halving), and there are two of them each time — so the count doubles at every level while depth stays n.
Unroll one layer at a time:
The pattern: after peeling layers, . Set to hit the base case : WHY (the geometric-series step): call the sum . Double it: . Subtract: (every middle term cancels), so . Substitute (): The term is a constant multiple of . Answer: — naive recursive Fibonacci lives here.
L4.3
You must generate every ordering of n distinct items to test each one. What is the complexity, and why is it worse than ?
Recall Solution
WHAT: the number of orderings (permutations) of n items is .
WHY worse than : compare factor-by-factor. Both are products of n numbers:
In every factor from 3 onward exceeds 2, so pulls ahead. Checking the crossover directly: at , but (so still leads); at , . So overtakes starting at and never looks back.
Answer: .
Level 5 — Mastery
(Subtle judgement calls where the "obvious" asymptotic answer is a trap.)
L5.1
For n = 10, which is larger: or ? For n = 3?
Recall Solution
n = 10: , → is larger.
n = 3: , → is larger.
WHY the crossover: starts below for tiny n but its doubling overtakes near and then explodes. Asymptotic order ( eventually wins) says nothing about small n.
Answer: at n=10; at n=3.
L5.2
Algorithm P is with a huge hidden constant (say operations). Algorithm Q is with a tiny constant ( operations). Below roughly what n does the "worse" quadratic algorithm actually run fewer operations?
Recall Solution
WHAT we compare: we want the values of n where Q is cheaper, i.e. where
Simplify: divide both sides by n (positive, so the inequality direction is safe):
Q is cheaper exactly while n stays below the value where the two sides are equal.
Bracket the crossover by testing values:
- at : , so → right side bigger → Q wins.
- at : , so → left side bigger → P wins.
So the crossover sits between and . Narrowing further (solving numerically) lands near .
WHY this happens: Big-O hides constants; a large enough constant keeps the "slower" class cheaper until
ngrows past the crossover. Answer: fornup to roughly (crossover near ) the algorithm does fewer operations; beyond that the one wins.
L5.3
An algorithm runs in the worst case but on already-sorted input. A colleague reports it as "an algorithm." Are they right? Which class label is honest, and why does this connect to 3.1.03-Best-Worst-Average-Case?
Recall Solution
WHAT is going on: the running time depends on the shape of the input, not just its size — best case , worst case . WHY "O(n)" is misleading: unless the input is guaranteed sorted, the honest guarantee is the worst case, . Reporting only the best case hides the failure mode. The nuance: both labels are true statements about different cases. State which case you mean (this is exactly the best/worst/average distinction). Answer: The honest headline is (worst case); is only the best case. Always name the case.