⚔ Big-O & Complexity

How we measure the speed of an algorithm

← Back to Algorithms

ā±ļø Why measure speed?

Two programs can solve the same problem, but one might take a millisecond and the other a full minute. As the amount of data grows, that gap explodes. Big-O notation is the language we use to describe how an algorithm's work grows as the input gets bigger.

We don't measure in seconds (computers differ!). Instead we count how many steps the algorithm takes relative to the input size, which we call n.

šŸ“ˆ The common complexities

Big-ONameExampleSpeed
O(1)ConstantGet list[0]šŸš€ Fastest
O(log n)LogarithmicBinary search⚔ Excellent
O(n)LinearOne loop over a listšŸ‘ Good
O(n log n)LinearithmicMerge sortšŸ™‚ Decent
O(n²)QuadraticNested loops🐢 Slow
O(2ⁿ)ExponentialNaive recursionšŸ’€ Avoid!

šŸŽÆ O(1) — Constant time

The work is the same no matter how big the data is. Grabbing one item by its index is instant:

def first(items): return items[0] # one step, always

āž”ļø O(n) — Linear time

The work grows in direct proportion to the input. One loop = O(n):

def total(items): s = 0 for x in items: # runs n times s += x return s

Double the list, and it takes about double the steps.

🐢 O(n²) — Quadratic time

A loop inside a loop means n Ɨ n steps. This gets slow fast — 100 items = 10,000 steps!

def has_duplicate(items): for i in items: # n times for j in items: # n times each ... # n Ɨ n = n² steps

šŸ“ The rules of Big-O

Simplify, simplify

  • Drop constants: O(2n) becomes O(n). We care about growth, not exact counts.
  • Drop smaller terms: O(n² + n) becomes O(n²). The biggest term dominates.
  • Worst case: Big-O usually describes the slowest possible run.

āœ… What you learned

  • Big-O describes how work grows with input size n.
  • One loop → O(n). Nested loops → O(n²). No loop → O(1).
  • Halving the problem each step → O(log n).
  • Drop constants and smaller terms when simplifying.