notes to self

Big O notation · part 1 of 8

What big O actually is

Big O notation can be broken down like this: n is the size of the input, and big O describes how the amount of work grows as n grows.

The main thing to remember is that it's about how it scales, not about speed (even though people use it to understand how fast something is).

Two quick examples from the van. First, our till looks up a price by flavour:

const prices = new Map([
  ["vanilla", 2.5],
  ["strawberry", 2.8]
  // ...the rest of the menu
]);

function priceOf(flavour) {
  return prices.get(flavour); // one hop, whatever the menu size
}

A Map jumps straight to the slot for that key. It's one lookup, regardless of whether the menu has five, or five thousand flavours. As the work doesn't grow with n at all, we call that O(1), constant time.

Now let's check if a flavour is still in stock, where stock is a plain list:

function inStock(stock, flavour) {
  for (const item of stock) {
    if (item.flavour === flavour) return item.scoops > 0;
  }
  return false;
}

Here we walk the list until we find it. If we have twice as many items, it's twice as much work (on average, as you might get lucky and spot it early). The work grows in line with n, so this is O(n), linear time.

O(1) versus O(n) is not "fast versus slow". For a stock list with three items on it, the loop finishes before you've blinked. Big O is about how the work grows, not how long it takes today.

You check whether a flavour is in stock by scanning a list of n items one by one. What's the time complexity?
Show answer

O(n) is the one.

You touch up to n items, one per loop, so the work grows in step with the list. That's linear, O(n). It would only be O(1) if you could jump straight to the answer, the way a Map does.

The shapes

There's a small family of these growth curves that run from "doesn't care how big n gets" all the way to "don't even think about it".

Have a play around with the chart below and drag the input size to see what each shape does. You don't need to know what each name means yet, that's what the rest of the series is for, just watch how differently they grow.

Operations as the input n grows. Drag to explore, or read the table.
The exact numbers
Complexityn = 10n = 100n = 1,000n = 1,000,000
O(1) constant1111
O(log n) logarithmic~3~7~10~20
O(n) linear101001,0001,000,000
O(n log n) linearithmic~33~664~9,966~19,931,569
O(n²) quadratic10010,0001,000,0001,000,000,000,000
O(2ⁿ) exponential1,024≈ 1.3 × 10³⁰≈ 1.1 × 10³⁰¹a 301,030-digit number
O(n!) factorial3,628,800≈ 9.3 × 10¹⁵⁷≈ 4.0 × 10²⁵⁶⁷a 5,565,709-digit number

Note that O(1) and O(log n) stay flat along the bottom: you can throw input at them all day. O(n) climbs in a straight (linear) line. O(n²) starts to curl upward and quickly gets out of control. And O(2ⁿ) and O(n!) rocket faster than SpaceX's IPO.

The right O for the job

Picking O(n) over O(n²) for the same job is the difference between a function that's fine at a million rows and one that times out during the bank holiday rush at our ice cream van.