Skip to content
DSA in JavaScript
Foundations

Big O & Complexity

Fundamentals · Starter

Level: Starter

Big O describes how the work an algorithm does grows as the input grows. It ignores machine speed and constants and keeps only the shape of the growth. It is the vocabulary every other topic here uses.

Common growth rates

NotationNameExamplen = 1,000,000
O(1)ConstantArray index, Map lookup1
O(log n)LogarithmicBinary searchabout 20
O(n)LinearOne loop over the input1 million
O(n log n)LinearithmicMerge sort, Array.sortabout 20 million
O(n²)QuadraticNested loops over the input1 trillion
O(2ⁿ)ExponentialAll subsetshopeless
O(n!)FactorialAll permutationshopeless

How to calculate it

  • Drop constants. 3n and n + 100 are both O(n).
  • Keep the dominant term. n² + n is O(n²).
  • Sequential steps add, nested steps multiply. Two loops one after the other: O(n + m). A loop inside a loop: O(n × m).
  • Different inputs get different letters. Looping over a then over b is O(a + b), not O(n).
  • Halving each step is log n. Anything that cuts the problem in half per step (binary search, balanced tree height) is O(log n).

Counting memory (space)

Count the extra memory you allocate, including the recursion call stack. A recursive function that goes n calls deep uses O(n) stack space even if it allocates nothing else.

Best, average, worst, amortised

Big O usually means the worst case. Quicksort is O(n log n) on average and O(n²) in the worst case. Amortised cost averages over a sequence: array.push is occasionally O(n) when the array grows, but O(1) amortised.

Cost of common JavaScript operations

OperationCost
arr[i], arr.push, arr.popO(1)
arr.shift, arr.unshift, arr.splice in the middleO(n)
arr.indexOf, arr.includes, arr.findO(n)
arr.slice, [...arr], arr.concatO(n)
arr.sortO(n log n)
map.get, map.set, set.has, set.addO(1) average
str + str in a loopO(n²) overall, prefer array.join

What the input size tells you

Interview constraints hint at the target complexity.

Input size nAim for
up to 10O(n!) is fine
up to 20O(2ⁿ)
up to 500O(n³)
up to 5,000O(n²)
up to 100,000O(n log n)
up to 1,000,000O(n)
largerO(log n) or O(1)

Code

BigO.js
// One example per growth rate. `n` is the input size.

const constant = arr => arr[0]; // O(1)

function logarithmic(n) { // O(log n): halve until 1
  let steps = 0;
  while (n > 1) { n = Math.floor(n / 2); steps++; }
  return steps;
}

const linear = arr => arr.reduce((sum, x) => sum + x, 0); // O(n)

function quadratic(arr) { // O(n^2): every pair
  const pairs = [];
  for (const a of arr) for (const b of arr) pairs.push([a, b]);
  return pairs;
}

function subsets(arr) { // O(2^n): each item in or out
  return arr.reduce((all, x) => all.concat(all.map(s => [...s, x])), [[]]);
}

// Two inputs means two variables: O(a + b), not O(n).
const both = (a, b) => [...a.map(x => x * 2), ...b.map(x => x + 1)];

export { constant, logarithmic, linear, quadratic, subsets, both };

Spotted a mistake or something unclear? Report it on GitHub.

On this page