Notes from production
Big-OAlgorithmsComplexity

Big-O notation for everyday code, explained

Big-O answers one question: as the data grows, how fast does the work grow? Not seconds on a wall clock — that changes with the machine — but the shape of the growth. Once you can read the shape, you can tell at a glance whether code that's smooth at 10 rows will still be smooth at 10 million.

The good news: nearly all everyday code falls into a handful of shapes, and each shape is born from a pattern you can spot on sight — if/else, a single loop, a nested loop, recursion, and binary search. Let's take them one at a time: the code, the graph, then why that code produces that shape.

O(1) — constant time

Pattern: one decision with a fixed number of branches. if/else, switch, array access by index, a hash-map read or write.

function paymentStatus(order) {
  if (order.paid) return "paid"
  return "unpaid"
}
n →O(1)
A flat line — cost doesn't grow as n grows.

O(log n) — logarithmic

Pattern: each step throws away half of the remaining work. The classic is binary search and operations on a balanced tree.

function search(sorted, target) {
  let lo = 0, hi = sorted.length - 1
  while (lo <= hi) {
    const mid = (lo + hi) >> 1
    if (sorted[mid] === target) return mid
    if (sorted[mid] < target) lo = mid + 1
    else hi = mid - 1
  }
  return -1
}
n →O(log n)
Steep early, then flat — throws away half each step.

O(n) — linear

Pattern: a single loop that touches each item exactly once.

function total(numbers) {
  let sum = 0
  for (const n of numbers) sum += n
  return sum
}
n →O(n)
A straight line — cost rises with n at a steady rate.

O(n log n) — linearithmic

Pattern: "divide then combine." Good sorting algorithms (merge sort, quicksort) live here.

const sorted = [...numbers].sort((a, b) => a - b)
// merge sort: splits the data into log n levels,
// then merges n items at each level
n →O(n log n)
Just above linear, curving up — divide then combine.

O(n²) — quadratic

Pattern: a loop inside a loop, pairing each item with every other item.

function hasDuplicate(arr) {
  for (let i = 0; i < arr.length; i++)
    for (let j = i + 1; j < arr.length; j++)
      if (arr[i] === arr[j]) return true
  return false
}
n →O(n²)
A parabola — double n means four times the work.

O(2ⁿ) — exponential

Pattern: branching recursion — each call spawns several new calls.

function fib(n) {
  if (n < 2) return n
  return fib(n - 1) + fib(n - 2)
}
n →O(2ⁿ)
A wall — it explodes almost vertically as n nudges up.

The leaderboard

Stacked side by side, the order is plain — from costs that barely move to costs that explode:

1O(1)constant2O(log n)logarithmic3O(n)linear4O(n log n)linearithmic5O(n²)quadratic6O(2ⁿ)exponential
Leaderboard: cheapest at the top, most expensive at the bottom as data grows.

A few rules of thumb you can apply while reading code:

  • One loop adds a factor of n.
  • Nested loops multiply by n again (two levels → n², three → n³).
  • Halving each step divides it down to log n (binary search, balanced trees).
  • "Divide then combine" gives n log n (good sorts).
  • Branching recursion explodes into exponential — usually a sign you need memoization or a different approach.

And don't forget: O(1) wins asymptotically, but constants still matter in the real world. A lean O(log n) can beat a heavy O(1) for every realistic n. Big-O tells you how code scales, not exactly how fast it runs today.

Sources

  1. Big-O Cheat Sheet — data structure & algorithm complexity
  2. MDN — Algorithm (glossary)
  3. Wikipedia — Time complexity