Big O Notation Explained- A Complete Guide
What the Heck is Big O Notation?
Big O notation describes how an algorithm performs as input size grows. That's it. Nothing fancy.
When developers talk about "O(n)" or "O(log n)", they're measuring the worst-case scenario for how long an algorithm takes or how much memory it uses. The "O" stands for "order of" — the order of magnitude.
You need this because writing code that works is step one. Writing code that scales is step two. Big O helps you see the difference before your app crashes at 10,000 users.
The Math Is Simpler Than You Think
Big O throws away constants and less significant terms. If your algorithm takes 5n² + 3n + 2 operations, it's O(n²). The 5, the 3n, and the 2 don't matter at scale.
Why? Because when n = 1,000,000, the n² term dominates everything else. Math works this way. Deal with it.
Common Complexities Ranked (Best to Worst)
| Notation | Name | Example |
|---|---|---|
| O(1) | Constant | Array index lookup |
| O(log n) | Logarithmic | Binary search |
| O(n) | Linear | Simple loop |
| O(n log n) | Linearithmic | Merge sort |
| O(n²) | Quadratic | Nested loops |
| O(2ⁿ) | Exponential | Recursive Fibonacci |
| O(n!) | Factorial | Brute-force traveling salesman |
Anything above O(n²) is practically unusable for real inputs. If your code hits O(2ⁿ), you've got a problem — unless your input never exceeds 20 elements.
O(1) — The Golden Standard
Hash table lookups. Array access by index. These take the same time regardless of input size. That's O(1).
Real-world example:
let arr = [10, 20, 30, 40, 50];
console.log(arr[3]); // Always one operation
Doesn't matter if the array has 5 elements or 5 million. Accessing index 3 is instant.
O(log n) — The Power of Halving
Binary search is the textbook example. Each step cuts the problem in half.
Think of guessing a number between 1 and 100. You guess 50. Too high? Now you only have 1-49. Guess 25. Too low? Now 26-49. You eliminate half every time.
That's logarithmic time. For 1 billion items, you need at most 30 guesses. That's why search algorithms love this complexity.
O(n) — Linear Time
You look at every element once. A basic for loop searching for a value in an unsorted array:
function findValue(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) return i;
}
return -1;
}
Double the input size, double the worst-case time. Simple math.
O(n²) — Where Things Get Ugly
Nested loops are the usual suspect. Bubble sort. Comparing every element to every other element.
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length; j++) {
// Something happens
}
}
100 items? 10,000 operations. 1000 items? 1,000,000 operations. This grows fast.
Bubble sort exists because it's easy to understand, not because it's efficient. Don't use it in production.
Time Complexity vs Space Complexity
Big O isn't just about time. It measures both:
- Time complexity — how many operations your algorithm needs
- Space complexity — how much memory your algorithm uses
Sometimes you trade one for the other. Caching results speeds up runtime but uses more memory. This is a fundamental tradeoff in system design.
Space Complexity Examples
Creating a new array of the same size: O(n) space. Recursion depth of n: O(n) space. A single variable: O(1) space.
How to Analyze Any Algorithm
Follow these steps:
- Identify the input size n
- Count the fundamental operations (comparisons, assignments)
- Express the count as a function of n
- Drop constants and lower-order terms
- Keep only the dominant term
Example: What's the complexity of finding the largest number in an array?
function findMax(arr) {
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
One pass through n elements. O(n). Space usage stays constant regardless of input size. O(1) space.
Common Patterns to Memorize
- Single loop → O(n)
- Loop inside loop (both depend on n) → O(n²)
- Halving the problem each iteration → O(log n)
- Recursion with two branches → O(2ⁿ)
- Sorting typically → O(n log n) is the best you can do for comparison sorts
Getting Started: Analyze Your Own Code
Pick a function you've written recently. Ask:
- How does runtime change if input doubles?
- Where are the loops? How deep?
- Are you using built-in methods? Do you know their complexity?
Most array methods in JavaScript are O(n) for searching. push() and pop() on the end of an array are O(1). shift() and unshift() are O(n) because everything needs to shift.
Choosing the right data structure is half the battle. Arrays give you fast access by index. Sets and Maps use hash tables for O(1) lookups. Trees and graphs enable O(log n) operations with sorted data.
The Brutal Truth
Most developers never calculate Big O for their code. They debug when things are slow instead.
You don't need to be a algorithms expert to write good software. But you do need to recognize when your code is about to hit O(n²) with user-generated content, or when a recursive solution will blow your stack at scale.
Know the common complexities. Understand the difference between O(n) and O(log n) — one works at scale, the other doesn't. That's 80% of what matters.