Skip to main content

fundamentals

Big-O & Complexity

A mental model for reasoning about how an algorithm's time and memory usage scale with input size — the foundation of every performance conversation in engineering.

beginner

What Is Big-O?

Big-O notation describes an upper bound on how an algorithm's cost grows as input size n grows. It captures the dominant term and drops constants so you can compare algorithms on the same scale.

NotationNameCommon examples
O(1)ConstantHash map lookup, array index
O(log n)LogarithmicBinary search, balanced tree ops
O(n)LinearSingle pass through an array
O(n log n)Log-linearMerge sort, heap sort
O(n²)QuadraticNested loops over same input
O(2ⁿ)ExponentialNaive subset enumeration

How to Reason About It in Practice

When you see a loop, ask: how many iterations, and what does each cost?

  • One loop over n items → O(n)
  • Two nested loops over n items → O(n²)
  • Halving the input each step → O(log n)
  • Building all subsets → O(2ⁿ)

Space complexity follows the same logic applied to memory allocations.

Memoization Pays Off

Naive recursive Fibonacci is O(2ⁿ) because it recomputes overlapping subproblems. Memoization collapses that to O(n).

Without @cache this call tree is exponential. With it, each unique n is computed once and stored.

When Big-O Misleads You

Big-O describes growth, not absolute speed — and that gap matters. It deliberately drops constants and lower-order terms, so an O(n) algorithm with heavy per-element work can lose to an O(n²) one when n is small. Real data is often small. Profile before "optimizing" a quadratic that only ever sees fifty items.

It also says nothing about constant factors that dominate in practice: cache locality, allocation, and I/O frequently outweigh the asymptotic class. Treat Big-O as the first filter on a design, not the last word — the right answer is "O(n log n), and I measured it on realistic input."

Related Concepts

beginner

Python Speed Kit

The standard-library tools that replace hand-rolled data structures: Counter, defaultdict, deque, heapq, bisect, and functools.cache — what each does, when to reach for it, and when not to.

intermediate

DAG Orchestration

Directed Acyclic Graphs (DAGs) model task dependencies so an orchestrator can run independent tasks in parallel and detect illegal cycles before execution — the backbone of workflow engines and job pipelines.