Big O Made Human: The Only Guide You'll Ever Need
If you don't know Big O, half of what developers say sounds like sorcery. This walks it from scratch — growth, constants, worst case — with TypeScript you can actually look at.
Okay, so here's the deal: if you don't know Big O, then a lot of what developers say will sound like sorcery. Like, "oh, this algorithm is O(n²)," and you're just standing there like, "cool cool cool… what does that mean again?"
Don't worry. We're going to walk through Big O from scratch — actually understand it, not just memorise the cheat sheet. We'll break it down like we're explaining it to our past selves. And I'll toss in some TypeScript, because I want you to see it, not read theory and hope it sticks.
So what the heck is Big O?
Big O is a way to talk about how an algorithm scales — how its performance grows as the input grows. That's it. If your function gets slower when you throw more data at it, Big O describes how much slower.
Here's the catch: Big O is not about exact numbers. Nobody says "this algorithm takes 450 CPU units." First off, what's a CPU unit? Second, even if you could measure it, it's irrelevant. Big O is general. It's about growth, not specifics.
So, first big idea:
Growth is with respect to input size.
Example: reading a string
Let's say we've got a string. Something simple like "hello".
function logCharacters(input: string): void {
for (let i = 0; i < input.length; i++) {
console.log(input[i]);
}
}
This logs each character. Pass in a 5-character string, it logs 5 times. Ten characters, ten logs. Growth is linear:
O(n) — linear time.
For every extra character, the function does one more thing. One-to-one. Easy.
How do you find Big O?
Here's the magic trick:
Look for loops.
That's it. Where do you loop over your input? Boom — now you're speaking the language of Big O.
Wait, what about constants?
Let's say we do this:
function doItTwice(input: string): void {
for (let i = 0; i < input.length; i++) {
console.log(input[i]);
}
for (let i = 0; i < input.length; i++) {
console.log(input[i].toUpperCase());
}
}
You might be tempted to say "ah, that's O(2n)!" But no.
We always drop constants.
It's still O(n). If your algorithm is linear, doing it twice or ten times doesn't change how it scales. It changes how fast it runs in practice. We're not measuring exact speed — we're measuring the shape of the growth.
The common complexities
Here's your cheat sheet, humanised:
n², n³, and spotting complexity
Take a look:
function logPairs(input: string): void {
for (let i = 0; i < input.length; i++) {
for (let j = 0; j < input.length; j++) {
console.log(input[i], input[j]);
}
}
}
You're looping over the input twice, nested: O(n²).
Triple loop? You guessed it — O(n³). Like multiplying 3D matrices.
But why does any of this matter?
Because understanding Big O helps you pick the right tool. Use a hash map when you want O(1) lookup. Use a heap when you want fast inserts and removes in sorted order. Use a ring buffer when you care about memory and performance in a FIFO world.
And yes — sometimes an O(n²) algorithm is faster than an O(n log n) one, if the input is tiny.
In practice, constants matter. In theory, they don't.
How to ace this in an interview
Three things:
- Growth is with respect to input.
- Drop constants.
- Assume worst case.
Remember those and you'll always have a handle on the conversation. Most interviewers aren't expecting a mathematician. They want to see that you understand how your code scales.
So next time you write a function, ask:
- Am I looping over the input?
- Am I looping inside a loop?
- Am I searching, or sorting?
That's all you need to get started with Big O.
P.S. — my favourite algorithm? Quicksort. Recursive, elegant, and O(n log n) in the average case. Favourite data structure to work with, though: the ring buffer. Just makes me feel like I'm doing something slick.