Big-O, time complexity, and space complexity
coreintermediateBig-O describes how an algorithm's cost grows as input size grows, ignoring constant factors. Time complexity measures growth in operations; space complexity measures growth in memory — both are about the SHAPE of growth.
Think of it as
Big-O answers "what happens if the input gets 10x bigger?" — not "how many milliseconds does this take right now." O(n) means 10x the input costs roughly 10x the work; O(n²) means 10x the input costs roughly 100x the work — the shape of the curve, not today's exact number.
What we're doing: Measure O(n) vs O(n²) duplicate-detection on the same real input and see the growth-rate difference directly.
- 3
- A set lookup (item in seen) is O(1) — this whole function is O(n): one pass, constant work per item.
- 11
- The nested loop compares every pair — O(n²) work, even though it does the exact same logical job.
O(n): 0.00056s
O(n^2): 0.32827s
n^2 version is 584x slowerWhy this works: Both functions solve the exact same problem (find a duplicate) and return the same answer — but the O(n²) version compares every pair, so at 5,000 items it does roughly 12.5 million comparisons versus the O(n) version's 5,000. The exact multiplier varies run to run (measured 500x-900x across repeated runs, since the O(n) time is tiny and noisy) — but the gap stays in the hundreds-of-times range every time, which is Big-O's abstract growth rate made concrete.
Optimizing constant factors while the algorithm stays O(n²)
Wrong
Better
What you see: A "faster" version still grinds to a halt on larger inputs, because micro-optimizing the inner loop only shrinks the constant factor — the O(n²) shape is unchanged.
Why: Big-O is about the SHAPE of growth. Shaving milliseconds off each comparison in an O(n²) algorithm still leaves it O(n²) — at large enough input, an unoptimized O(n) algorithm always eventually wins.
- O(1): Small n, Cheap — dict[key], set membership — flat, always
- O(log n): between Small n and Large n, Cheap — binary search — grows very slowly
- O(n): between Small n and Large n, between Cheap and Expensive — a single loop over n items
- O(n log n): Large n, between Cheap and Expensive — sorted(), list.sort()
- O(n²): Large n, Expensive — nested loop — measured 584x slower at n=5000
Common complexities, smallest to largest
Together
Remember: Big-O describes how cost grows with input size, not today's runtime — O(n) eventually beats O(n²), however tuned.
See also: choosing data structures · measure first optimize second

