Quick Context
The six classes you will encounter most often are O(1) constant, O(log n) logarithmic, O(n) linear, O(n log n) linearithmic, O(n²) quadratic and O(2ⁿ) exponential.
Why Ignore the Constants?
Because hardware changes and growth does not. A machine twice as fast halves every constant, but an O(n²) algorithm is still O(n²) — double the input and you quadruple the work, forever.
Slide n and watch the table. At n = 10 every row looks affordable. By n = 1000 the quadratic column is a million operations and the exponential column has left the universe behind.
The Six Classes You Will Meet
- O(1) constant — cost stays bounded as n grows. Array index lookup and stack push are typical; hash-table lookup is expected O(1), not a worst-case guarantee.
- O(log n) logarithmic — each step halves the problem. Binary search, balanced tree operations. Doubling n adds just one step.
- O(n) linear — touch every item once. Linear search, summing an array.
- O(n log n) — common for efficient comparison sorts. Merge sort and heapsort have this worst-case bound; quicksort is O(n log n) on average but O(n²) in the worst case.
- O(n²) quadratic — often comes from nested loops over the data. Bubble, insertion and selection sort have quadratic worst cases; simple versions can still suit small or nearly sorted inputs.
- O(2ⁿ) exponential — every extra element doubles the work. Naive recursive Fibonacci, brute-force subsets. Intractable beyond roughly n = 40.
Compare the growth rates
| Complexity | Name | n = 10 | n = 1,000 | n = 1,000,000 |
|---|
| O(1) | Constant | 1 | 1 | 1 |
| O(log n) | Logarithmic | 3 | 10 | 20 |
| O(n) | Linear | 10 | 1,000 | 1,000,000 |
| O(n log n) | Linearithmic | 30 | 10,000 | 20,000,000 |
| O(n²) | Quadratic | 100 | 1,000,000 | 10¹² |
| O(2ⁿ) | Exponential | 1,024 | astronomical | impossible |
The table shows growth, not wall-clock time: actual duration depends on the operation, implementation and hardware. At n = 1,000,000, the listed O(n log n) model is about 20 million units of work, while the quadratic model is 10¹². Their ratio illustrates why input growth can dominate constant-factor tuning.
Reading complexity from code
The rules are mechanical once you see them.
A loop over the input is O(n).
Nested loops multiply. Two loops over n is O(n²); three is O(n³).
Sequential loops add, and the larger term wins: O(n) + O(n²) = O(n²).
Halving the search space each step is O(log n). Binary search on a million items takes 20 steps, because 2²⁰ ≈ 1,000,000.
Dictionary and set lookups are expected O(1). Hash collisions can make a lookup slower, so this is not a worst-case guarantee.
# O(n^2) - for each item, scan the whole list
for a in items:
if a in other_list: # this scan is O(n)
...
# O(n) - build a set once, then constant-time lookups
other = set(other_list)
for a in items:
if a in other: # expected O(1)
...
That transformation — replacing a repeated scan with a pre-built set or dictionary — is the most common and most effective optimisation in everyday code, and it usually makes the code shorter as well.
Things to try with Big-O Notation and Time Complexity
- Start at n = 10. Every curve is bunched together — at small inputs, complexity genuinely does not matter and the constants dominate.
- Slide to n = 60. The exponential curve leaves the chart almost immediately, then the quadratic. The separation is the entire point of the notation.
Space complexity
The same notation applies to memory, and it is frequently the binding constraint.
| Approach | Time | Space |
|---|
| Sort in place | O(n log n) | O(1) extra |
| Merge sort | O(n log n) | O(n) extra |
| Recursion depth d | — | O(d) stack |
| Memoised Fibonacci | O(n) time | O(n) extra |
Recursion's space cost is easy to overlook: each active call holds a frame, so depth n uses O(n) stack space. Python limits recursion depth; the configured limit varies by environment. Deep input may need an iterative solution or an explicit stack.
Memoisation is a time-for-space trade: naive recursive Fibonacci takes O(2ⁿ) time and O(n) stack space, while memoised Fibonacci takes O(n) time and O(n) total extra space. The improvement comes from computing each state once.