Big-O Complexity
A shorthand for how the work an algorithm does grows as its input grows. It is the language interviewers use to ask "will this still be fast when the data gets big?"
Big-O is a way of describing how the amount of work an algorithm does grows as its input grows. It throws away all the details that don't matter at scale, the exact hardware, the constant setup costs, the small terms, and keeps only the part that dominates when the input gets large. When an interviewer asks "what's the complexity?" they are really asking: if I ten-times the data, does your runtime barely move, ten-times, or explode?
The reason it matters is that constants lie and growth rates don't. An algorithm that does 100n operations beats one that does n² the moment n passes 100, and from there the gap only widens. On a million-element array, an method finishes in a blink while an method does a trillion steps and effectively never returns. Getting the growth rate right is usually the difference between a solution that passes and one that times out.
We write
to mean: beyond some input size, the running time is at most a constant multiple of . Here is the size of the input (array length, number of nodes), is the growth shape we care about (, , , …), and the hidden constant is exactly what Big-O lets us ignore. So and are the same class: both grow linearly.
The classes worth knowing cold
| Big-O | Name | Where it shows up |
|---|---|---|
| constant | hash lookup, array index, stack push | |
| logarithmic | binary search, balanced-tree / heap operations | |
| linear | one pass over an array, two-pointer scans | |
| linearithmic | good sorting, heap-based top-k | |
| quadratic | nested loops over the same array | |
| exponential | brute-forcing every subset |
Worked example: does this list have a duplicate?
Two ways to check whether an array of n numbers contains any repeat.
The nested-loop way compares every element to every other one:
def has_dup_slow(a): # O(n^2) time, O(1) space
for i in range(len(a)):
for j in range(i + 1, len(a)):
if a[i] == a[j]:
return True
return False
The outer loop runs n times, the inner up to n times, so the work is proportional to . The hash-set way remembers what it has seen:
def has_dup_fast(a): # O(n) time, O(n) space
seen = set()
for x in a:
if x in seen:
return True
seen.add(x)
return False
One pass, and each in/add on a set is on average, so the whole thing is . Put numbers on it: at , the slow version does about 50 million comparisons; the fast one does 10,000 lookups. That is a 5,000-times difference, and it grows with n. The trade is memory: the fast version stores up to n items, so it is space. Reporting both time and space is what interviewers want.
Big-O keeps only the dominant term and drops constants: is just . The whole skill is spotting which term wins as grows large, then naming its shape.
Reading complexity off code
Two quick rules cover most interview code. Sequential blocks add (); nested loops multiply (a loop of n inside a loop of n is ). Halving the search space each step, as binary search does, gives , because you can only halve n about times before nothing is left.
Fast heuristic: sequential loops add, nested loops multiply, halving gives a log. Sorting is your friend, it is and often turns an brute force into an or scan.
Where it misleads
- Constants matter at small
n. can beat on tiny inputs, which is why real sort routines switch to insertion sort under a threshold. Big-O is an asymptotic claim. - Worst case is not average case. A hash lookup is on average but if every key collides; quicksort is typically but on an adversarial input. Say which case you mean.
- Space counts too. A blazing -time method that allocates an hash map may lose to an in-place one under a tight memory limit.
does not mean "instant" and does not mean "slow", they describe growth, not raw speed. Always state whether you mean best, average, or worst case, and always give the space complexity alongside the time.
In quant-dev interviews, complexity is the very first thing you say after describing an approach and the last thing you check before coding: "this is time, space, can we do better?" Being fluent in it lets you compare the Arrays and Two Pointers, Hash Maps and Sets, and Binary Search Patterns tricks and pick the one that fits the size of the data.
Related concepts
Practice in interviews
Further reading
- Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms (ch. 3)
- Skiena, The Algorithm Design Manual (ch. 2)