3.1.2 · D5Complexity Analysis

Question bank — Common complexities — O(1), O(log n), O(n), O(n log n), O(n²), O(n³), O(2ⁿ), O(n!)

1,512 words7 min readBack to topic

Before we start, one shared vocabulary reminder so no symbol is unearned:

  • = the size of the input (how many items you feed the algorithm).
  • = the step count — roughly how many basic operations run for that input.
  • = an upper bound on growth for large , with constants and smaller terms dropped (see 3.1.01-Big-O-Notation).

True or false — justify

TF — "An algorithm that is can never be faster than one that is ."
False. Big-O describes growth for large only; it hides constant factors, so an routine with a tiny constant can beat an one with a huge constant for small .
TF — " and describe the same class."
True. The constant is dropped in Big-O, so ; both grow linearly and only differ by a fixed multiplier that asymptotics ignore.
TF — " and are different complexity classes."
False. , so changing base is just multiplying by a constant — Big-O drops it, and both are simply .
TF — "If the input doubles and the runtime also doubles, the algorithm is ."
True. Runtime scaling in direct proportion to input is the defining signature of linear growth, .
TF — "If the input doubles and the runtime only goes up by a constant amount, the algorithm is ."
True. Doubling adds exactly one halving step (), so the extra cost is one constant chunk — the hallmark of logarithmic work.
TF — "Every recursive algorithm is exponential."
False. Recursion's cost depends on the recurrence: Merge-Sort is , Binary-Search is — both recursive, neither exponential.
TF — " is just a slightly slower version of ."
False. is a product of factors, most exceeding , so it overtakes from and pulls away hugely — at , vs , a different and worse class.
TF — "Big-O tells you the exact running time in seconds."
False. Big-O is a growth rate, not a wall-clock time; actual seconds depend on hardware, language, and hidden constants that Big-O deliberately discards.

Spot the error

Error — "Two loops one after the other, each running times, so it's ."
The error is multiplying sequential loops. Loops in sequence add: ; only nested loops multiply.
Error — "This while-loop subtracts from each step, so it's ."
Wrong signature. Subtracting a constant gives iterations; logarithmic requires dividing by a constant factor each step, not subtracting.
Error — "The inner loop runs from to , so on average it's half as much work, making it , which is better than ."
The is a constant and gets dropped: . A triangular loop is the same class as a full nested loop.
Error — "A hash-table lookup is always ."
That is the average case; worst-case (many collisions) can degrade to . See 3.1.03-Best-Worst-Average-Case — the guarantee depends on which case you mean.
Error — "Naive recursive Fibonacci is because there are levels of recursion."
Counting levels ignores branching: each call spawns two, giving a recurrence that grows like — memoizing it (see Dynamic-Programming) is what brings it to .
Error — " matrix multiplication has three nested loops, so tripling the matrix size triples the runtime."
Tripling multiplies runtime by , not . With three nested loops each running times, work scales as .
Error — "Since contains a log, it's slower than ."
Reversed. grows far slower than , so ; the linearithmic class sits below quadratic on the ladder.

Why questions

Why do we drop lower-order terms like the in ?
For large the term dwarfs the linear term, so it alone decides the growth rate; keeping smaller terms adds no information about how the work explodes.
Why is dividing the problem by a constant factor the "signature" of ?
Because after divisions by you have items; setting that to gives , so the number of steps is logarithmic in the starting size — see the derivation behind Recurrence-Relations.
Why doesn't the base of the logarithm affect the Big-O class?
Any two bases differ only by the constant factor , and Big-O ignores constant multipliers, so all logarithmic growth collapses into one class .
Why does arise so naturally from "take-or-skip" decisions?
Each of the items independently has choices, so the number of combinations is ; enumerating them all is inherently exponential.
Why can the Master-Theorem hand you for merge sort without unrolling the whole tree?
It matches to a known pattern where the per-level work is constant across all levels, immediately yielding .
Why are and algorithms called "intractable" for large ?
Their step counts grow so fast that even at operations per second the runtime exceeds human timescales for modest (e.g. factorial ≈ 77 years), which is why problems needing them are studied under NP-Completeness.
Why does overtake specifically from ?
Both are products of factors, but 's factors () start exceeding from the third onward, so their product first surpasses once enough factors accumulate — at , .

Edge cases

Edge — "What is the complexity of a loop that runs times but each iteration also loops times — except when ?"
Still ; the empty case does zero work, but Big-O describes the trend as , not the trivial base case.
Edge — "Is an algorithm that does exactly operations regardless of really ?"
Yes. A fixed, bounded number of operations — however large the constant — is constant time, because it does not grow with at all.
Edge — "For , binary search and linear search both finish in one step — so are they the same complexity?"
No. Complexity is about the growth trend as increases; agreement at a single tiny input says nothing about vs behaviour for large .
Edge — "A nested loop where the inner loop runs a fixed times regardless of — is that ?"
No, it's ; the inner loop's count doesn't depend on , so it's a constant factor () that reduces to linear.
Edge — "At , which is bigger, or , and does that change the ordering on the ladder?"
beats , and it does not change the ordering — exponential crossed quadratic near and stays above forever after.
Edge — "If constants don't matter, can I ignore them when choosing between two real implementations?"
Only for large ; for small inputs the hidden constants dominate, so an insertion sort can beat an merge sort below roughly — always profile small cases.

Recall One-line self-test

Say aloud the full ladder from fastest to slowest, then name the signature in code for each of , , , , , . Answer ::: ; signatures: constant = no loop over data; log = divide by a factor each step; linear = one pass; linearithmic = passes each linear (or divide-and-merge); quadratic = nested loop; exponential = binary take/skip branching.