Phase 1 · FoundationsModule 2~40 min read

Algorithm Analysis & Big-O

Measure how an algorithm's running time and memory grow with input size, independent of the machine it runs on.

What you'll learn

To compare algorithms fairly we need a measure that doesn't depend on your laptop, the language, or the weather. That measure is Big-O: how the amount of work grows as the input grows. Master it and you can predict which algorithm wins before writing a line of code.

By the end you'll be able to:

  • Explain why we measure growth, not raw seconds
  • Read O, Ω, and Θ notation
  • Analyze loops and recursion to find a function's complexity
  • Tell best, worst, and average case apart

Why we measure growth, not seconds

Raw timings lie: a slow algorithm on a fast machine can beat a fast algorithm on a slow one — for small inputs. What we really care about is scaling: when the input doubles, does the work double, quadruple, or barely move? Big-O captures exactly that, ignoring constant factors and lower-order terms so the essential behavior stands out. Drag the slider and watch how differently each class grows:

How complexity classes diverge
ops0input size n →
n = 8
ComplexityNameOperations at n = 8
O(1)Constant1
O(log n)Logarithmic3
O(n)Linear8
O(n log n)Linearithmic24
O(n²)Quadratic64
O(2ⁿ)Exponential256
O(n!)Factorial40,320
Small n hides everything; as n grows, the classes fan out by orders of magnitude.

Big-O, Big-Omega & Big-Theta

Three symbols pin down how a running time behaves as the input grows without bound:

  • O(f) — an upper bound. The algorithm grows no faster than f.
  • Ω(f) — a lower bound. It grows at least as fast as f.
  • Θ(f) — a tight bound. It's both O(f) and Ω(f).

Note

In everyday use, people say "Big-O" when they mean the tight bound Θ. We'll do the same, but it's worth knowing the difference — a bound can be loose (O(n²) is technically true for an O(n) algorithm, just not useful).

The complexity classes

These are the classes you'll meet again and again, from fastest-growing-slowest to catastrophic:

ClassNameExample
O(1)ConstantArray index; hash lookup
O(log n)LogarithmicBinary search
O(n)LinearScan a list
O(n log n)LinearithmicMerge sort, heap sort
O(n²)QuadraticNested loops; bubble sort
O(2ⁿ)ExponentialNaive subset enumeration
O(n!)FactorialBrute-force permutations

Analyzing code

Two rules do most of the work. Sequential steps add (and we keep the biggest); nestedloops multiply. Drop constants and lower-order terms at the end:

Language
complexity.py
def first(a):          # O(1) — one step, any size
    return a[0]

def total(a):          # O(n) — one pass over n items
    s = 0
    for x in a:
        s += x
    return s

def has_dupes(a):      # O(n²) — a pair of nested loops
    for i in range(len(a)):
        for j in range(i + 1, len(a)):
            if a[i] == a[j]:
                return True
    return False

first does a fixed amount of work → O(1). total touches each of n items once → O(n). has_dupes pairs every element with every later one → about n²/2 comparisons, which is O(n²). For recursion, write a recurrence and solve it — the subject of the next module.

Best, worst & average case

The same algorithm can do different amounts of work on different inputs. has_dupes returns immediately if the first two elements match (best case, O(1)) but scans everything when there are no duplicates (worst case, O(n²)). We usually quote the worst case — it's the guarantee — and sometimes the average case when the worst case is rare.

Key idea

Space has its own Big-O. An algorithm can be fast but memory-hungry (merge sort's O(n) extra space) or slow but frugal. Always ask about both time and space.

Recap & quick check

Key takeaways

  • Big-O measures how work grows with input size, ignoring constants and machines.
  • O is an upper bound, Ω a lower bound, Θ a tight bound; casual 'Big-O' means Θ.
  • Sequential steps add; nested loops multiply; drop constants and lower-order terms.
  • Know the ladder: O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2ⁿ) < O(n!).
  • Distinguish best, worst, and average case — and analyze space as well as time.

Quick check

1. What does Big-O notation describe?

2. What is the time complexity of two nested loops that each run n times?

3. Which is the tight bound notation?

4. Why do we usually report the worst case?

Loops are easy to analyze; recursion needs a new tool. Next up: Module 3 — Recursion, Recurrences & the Master Theorem.