Big-O Notation

Jump to...


Time Complexity

Complexity Classes

Time Complexity Algorithm
O(1) Constant
O(log n) Logarithmic
O(n) Linear
O(n log n) Linearithmic
O(n * log(n)) Loglinear
O(n2) Polynomial (Quadratic)
O(n 3 ) Polynomial (Cubic)
O(2 n ) Exponential
O(n!) Factorial

Click algorithm name for more details

O(1) Constant

Constant Growth

n O(1)
1 ~1
2 ~1
3 ~1
... ...
128 ~1

Example Constant Code

function constant1(n) {
  return n * 2 + 1;
}

function constant2(n) {
  for (let i = 1; i <= 100; i++) {
    console.log(i);
  }
}

O(log(n)) Logarithmic

Logarithmic Growth

n O(log2(n))
2 ~1
4 ~2
8 ~3
16 ~4
... ...
128 ~7

Example Logarithmic Code

function logarithmic1(n) {
  if (n <= 1) return;
  logarithmic1(n / 2);
}

function logarithmic2(n) {
  let i = n;
  while (i > 1) {
    i /= 2;
  }
}

O(n) Linear

Linear Growth:

n O(n)
1 ~1
2 ~2
3 ~3
... ...
128 ~128

Example Linear Code

function linear1(n) {
  for (let i = 1; i <= n; i++) {
    console.log(i);
  }
}

function linear2(array) {
  for (let i = 0; i < array.length; i++) {
    console.log(i);
  }
}

function linear3(n) {
  if (n === 1) return;
  linear3(n - 1);
}

O(n * log(n)) Loglinear

Loglinear Growth:

n O(n * log2(n))
2 ~2
4 ~8
8 ~24
... ...
128 ~896

Example Loglinear Code

function loglinear(n) {
  if (n <= 1) return;

  for (let i = 1; i <= n; i++) {
    console.log(i);
  }

  loglinear(n / 2);
  loglinear(n / 2);
}

O(nc) Polynomial

Polynomial Growth:

n O(n2)
1 ~1
2 ~4
3 ~9
... ...
128 ~16,384
n O(n3)
1 ~1
2 ~8
3 ~27
... ...
128 ~2,097,152

Example Polynomial Code

// O(n^2)
function quadratic(n) {
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= n; j++) {}
  }
}

// O(n^3)
function cubic(n) {
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= n; j++) {
      for (let k = 1; k <= n; k++) {}
    }
  }
}

O(cn) Exponential

Exponential Growth:

n O(2n)
1 ~2
2 ~4
3 ~8
... ...
128 ~3.4028 * 1038
n O(23)
1 ~3
2 ~9
3 ~27
3 ~81
... ...
128 ~1.1790 * 1061

Example Exponential Code

// O(2^n)
function exponential2n(n) {
  if (n === 1) return;
  exponential_2n(n - 1);
  exponential_2n(n - 1);
}

// O(3^n)
function exponential3n(n) {
  if (n === 0) return;
  exponential_3n(n - 1);
  exponential_3n(n - 1);
  exponential_3n(n - 1);
}

O(n!) Factorial

Factorial Growth:

n O(n!)
1 ~1
2 ~2
3 ~6
... ...
128 ~3.8562 * 10215

Example Factorial Code

function factorial(n) {
  if (n === 1) return;

  for (let i = 1; i <= n; i++) {
    factorial(n - 1);
  }
}

Sorting Algorithms

Complexity Classes of Common Sorting Methods

Sort Name Time Complexity Space Complexity
bubble O(n^2) O(1)
selection O(n^2) O(1)
insertion O(n^2) O(1)
merge O(n log n) O(n)
quick O(n log n)/O(n^2) O(n)/O(log n)
binary O(log(n)) O(1)

Click sort name for more details

Bubble Sort

Time Complexity: Quadratic O(n^2)

Space Complexity: O(1)

function bubbleSort(array) {
  let sorted = false;
  while (!sorted) {
    sorted = true;
    for (let i = 0; i < array.length; i++) {
      if (array[i] > array[i + 1]) {
        let temp = arr[i];
        array[i] = array[i + 1];
        array[i + 1] = temp;
        sorted = false;
      }
    }
  }
  return array;
}

Bubble Sort Pseudocode


Selection Sort

Time Complexity: Quadratic O(n^2)

Space Complexity: O(1)

function selectionSort(array) {
  for (let i = 0; i < array.length; i++) {
    let lowest = i;
    for (let j = 0; j < array.length; j++) {
      if (array[j] < array[i]) {
        lowest = j;
      }
    }
    if (lowest !== i) {
      let temp = array[i];
      array[i] = array[lowest];
      array[lowest] = temp;
    }
  }
  return array;
}

Selection Sort Pseudocode

selection


Insertion Sort

Time Complexity: Quadratic O(n^2)

Space Complexity: O(n)

function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    let current = arr[i];
    let j = i - 1;
    while (j > -1 && current < arr[j]) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = current;
  }
  return arr;
}

Insertion Sort Pseudocode

Merge Sort

Time Complexity: Log Linear O(nlog(n))

Space Complexity: O(n)

// Iterative merge
function merge(arr1, arr2) {
  let result = [];
  while (arr1.length && arr2.length) {
    if (arr1[0] < arr2[0]) {
      result.push(arr1.shift());
    } else {
      result.push(arr2.shift());
    }
  }
  return [...result, ...arr1, ...arr2];
}

// Recursive merge
function mergeSort(arr) {
  if (arr.length <= 1) return arr;

  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));

  return merge(left, right);
}

Merge Sort Pseudocode

mergesort


Quick Sort

Time Complexity: Quadratic O(n^2)

Space Complexity: O(n)

function quickSort(array) {
  if (array.length <= 1) return array;

  let pivot = array.shift();

  let left = array.filter((x) => x < pivot);
  let right = array.filter((x) => x >= pivot);

  let sortedLeft = quickSort(left);
  let sortedRight = quickSort(right);

  return [...sortedLeft, pivot, ...sortedRight];
}

Quick Sort Pseudocode

quick


Binary Search

Time Complexity: Log Time O(log(n))

Space Complexity: O(1)

Recursive Solution

function binarySearch(array, target) {
  if (array.length === 0) return false;

  let midPt = Math.floor(array.length / 2);

  if (array[midPt] === target) {
    return true;
  } else if (list[midPt] > target) {
    return binarySearch(list.slice(0, mid), target);
  } else {
    return binarySearch(list.slice(midPt + 1), target);
  }
}

Min Max Solution

function binarySearch(array, target) {
  let start = 0;
  let end = array.length - 1;

  while (start <= end) {
    let midpoint = Math.floor((start + end) / 2);

    if (target === array[midpoint]) {
      return midpoint;
    }

    if (target > array[midpoint]) {
      start = midpoint + 1;
    }

    if (target < array[midpoint]) {
      end = midpoint - 1;
    }
  }
  return -1;
}

Memoization


Tabulation

Main considerations for using tabulation:
Example of a tabulated fibonacci:
// Using tabulation
// Time Complexity: O(n)
//   - We are iterating through an array directly related to the size of the input and performing a constant number of calculations at each step (adding our two previous values together and storing the result in the array).
function fib(n) {
  // We create a table to track our values as we build them up
  // We're making it n+1 here so that table[n] lines up with the nth fib number
  // This is because arrays are zero-indexed.
  // We could have used an array of length n, but we would have to remember that
  // the nth fib number would then be stored at table[n-1]. Completely doable,
  // but I think making them line up is more intuitive.
  let table = new Array(n + 1);
  // Seed our table with our starting values.
  // Again, if we had a table of length n, we could have seeded table[0] = 1
  // and table[1] = 1 and had the same final result with our indices shifted.
  table[0] = 0;
  table[1] = 1;

  // Iterate through our input and fill out our table as we go.
  for (let i = 2; i < table.length; i++) {
    table[i] = table[i - 1] + table[i - 2];
  }

  // At the end, the final entry in our table is the result we are looking for.
  // The table holds all of the sub-answers that we used to get to this result.
  return table[n];
}