What Is Big-O Notation? A Concrete Beginner's Guide

- Big-O notation measures growth rate, not raw speed: it tells you how an algorithm slows down as input grows, not how many milliseconds it takes on your machine.
- Six complexity classes cover every interview case: O(1), O(log n), O(n), O(n log n), O(n²), and O(2^n), in that order from best to worst.
- Sequential loops add; nested loops multiply: two back-to-back loops over n elements is O(n), a loop inside a loop is O(n²).
- O(n²) to O(n) is the key interview move: a hash set swaps a nested loop for a single pass, at the cost of O(n) extra space.
- Always give both time and space complexity: "O(n)" alone leaves half the analysis on the table.
- Big-O ignores constants and cache effects: two O(n) algorithms can differ 100x in practice, and arrays beat linked lists despite identical asymptotic traversal costs.
You write a function that searches a list. It works. Your interviewer asks: "What's the time complexity?" You say "it's fast" and watch the energy drain from the room like someone pulled a plug.
Big-O notation is the vocabulary for that question. It tells you how an algorithm's resource usage grows as the input gets larger, not how many milliseconds it takes on your laptop. Once you can read it, you can compare any two approaches on a whiteboard without running a single benchmark, and more importantly, you can stop saying "it's fast" to people who need actual numbers.
It Measures Growth, Not Speed
Here's the thing that trips up beginners: Big-O is not a measurement of how fast your code runs. It's a measurement of how fast your code slows down.
A function that takes 1,000ms on 10 elements and 2,000ms on 20 elements has doubled in time for a doubled input. That's linear growth. Whether it runs in 1ms or 10 seconds is a hardware question. How it grows is a mathematical one.
Formally, when you say "this algorithm is O(n)," you're saying the operation count grows at most proportionally to n. Constants and lower-order terms get dropped because they become irrelevant at scale.
# O(3n) becomes O(n) -- the 3 doesn't matter at scale # O(n² + n) becomes O(n²) -- the n vanishes next to n²
The Six Classes You'll Actually Use
Every complexity class you'll encounter in a coding interview maps to one of these six shapes. Know them cold.
| Class | Name | Example |
|---|---|---|
| O(1) | Constant | Array index lookup |
| O(log n) | Logarithmic | Binary search |
| O(n) | Linear | Single loop over input |
| O(n log n) | Linearithmic | Merge sort |
| O(n²) | Quadratic | Nested loop over input |
| O(2^n) | Exponential | Generating all subsets |
How they grow:
| n | O(log n) | O(n) | O(n log n) | O(n²) | O(2^n) |
|---|---|---|---|---|---|
| 10 | 3 | 10 | 33 | 100 | 1,024 |
| 100 | 7 | 100 | 664 | 10,000 | 10^30 |
| 1,000 | 10 | 1,000 | 9,966 | 1,000,000 | 10^301 |
That last column is not a typo. O(2^n) at n=1,000 is a number with 300 digits. This is why "exponential time" is a conversation-stopper in interviews. Your machine could run until the heat death of the universe and still have 299 digits of work left.
O(1): The Lottery Winner
Constant time means the operation takes the same number of steps regardless of input size. Doesn't matter if your array has 10 elements or 10 million. The operation does the same work.
def get_first(items): return items[0] # O(1) -- one step, always
Hashtable lookups are O(1). Pushing to a stack is O(1). These are the building blocks interviewers love because they let you build fast data structures from slow-seeming pieces. Every time you reach for O(1), an interviewer somewhere smiles.
O(log n): The Halver
Each step cuts the remaining work in half. Binary search is the canonical example. You have a sorted array of a million elements and you want to find a value. You check the middle. Too high? Discard the right half. Too low? Discard the left half. Repeat until you win or admit defeat.
def binary_search(arr, target): left, right = 0, len(arr) - 1 while left <= right: mid = left + (right - left) // 2 if arr[mid] == target: return mid elif arr[mid] < target: left = mid + 1 else: right = mid - 1 return -1
The key insight: log₂(1,000,000) ≈ 20. You can find any value in a sorted million-element array in about 20 steps. That's why sorted data plus binary search is such a powerful combo in interview problems.
Balanced binary search trees work the same way. Any algorithm that repeatedly halves its search space lands here.
O(n): The Honest One
One pass through the input. The work scales directly with input size. A single loop over n elements is O(n). Two sequential single loops over n elements is still O(n), because 2n drops the constant.
def find_max(nums): maximum = nums[0] for num in nums: # O(n) if num > maximum: maximum = num return maximum
O(n) is often your target in interviews. If someone asks "can you do better than O(n²)?" the first goal is usually O(n) or O(n log n). Hitting O(n) feels like arriving on time after a fire drill. Everything settles down.
O(n log n): The Sorting Floor
You cannot sort a general list of n elements faster than O(n log n) using comparison-based sorting. This is a proven information-theoretic lower bound, not just an observation someone made after lunch. Merge sort, heap sort, and Timsort all land here.
The intuition: sorting n elements requires making decisions at each step, and each decision halves the remaining uncertainty. That produces n log n total decisions.
def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) # T(n/2) right = merge_sort(arr[mid:]) # T(n/2) return merge(left, right) # O(n) to merge # Total: T(n) = 2T(n/2) + O(n) = O(n log n)
When you see a sort call in your solution, add O(n log n) to your complexity analysis. Don't forget it. Interviewers notice.
O(n²): The Warning Sign
Nested loops over the same input. If you loop over an array and for each element you loop over the array again, you've done n times n steps.
def has_duplicate_naive(nums): for i in range(len(nums)): for j in range(i + 1, len(nums)): # nested loop if nums[i] == nums[j]: return True return False
This works. For a 1,000-element array it does roughly 500,000 comparisons. For a million elements: 500 billion. At that point, your interviewer is already writing "brute force only" in their notes and mentally moving on.

Someone implemented a Big-O detector that works by measuring indentation depth. They're not entirely wrong about nested loops.
The interview move is to ask: can I use a hash set to get this down to O(n)? Often yes.
def has_duplicate_fast(nums): seen = set() for num in nums: if num in seen: return True seen.add(num) return False # O(n) time, O(n) space
One loop, done. The hash set does the deduplication work in constant time per lookup.
O(2^n): The Combinatorial Explosion
Every time n grows by 1, the work doubles. This shows up when you're generating all subsets of a set, or doing naive recursive Fibonacci without memoization.
def fibonacci_naive(n): if n <= 1: return n return fibonacci_naive(n - 1) + fibonacci_naive(n - 2) # Recursion tree has ~2^n nodes
You'll see O(2^n) accepted in backtracking problems where you're explicitly required to enumerate all possibilities. Subsets, permutations, combinations. But if you have an O(2^n) DP solution, your interviewer will expect you to add memoization and bring it to O(n) or O(n²). Leaving it exponential is like ordering a salad and then eating the plate.
How to Read Code and Calculate Big-O Notation
Two rules cover 90% of interview cases.
Rule 1: Sequential operations add. One loop followed by another loop is O(n) + O(n) = O(2n) = O(n).
Rule 2: Nested operations multiply. A loop inside a loop is O(n) × O(n) = O(n²).
def example(arr): # Loop 1: O(n) for x in arr: print(x) # Loop 2: O(n) for x in arr: print(x * 2) # These add: O(n) + O(n) = O(n) def example2(arr): # Nested loops: O(n²) for i in arr: for j in arr: print(i, j)
The tricky case is when the inner loop doesn't run n times. In has_duplicate_naive above, the inner loop runs n-1, n-2, n-3... times. That sum is n(n-1)/2, which drops to O(n²) after the rules. Don't try to be clever with the arithmetic. It always collapses to the dominant term.
For recursive functions, you need the recursion tree: how many calls are made, and how much work happens at each node? Merge sort makes 2 calls at each level and does O(n) merge work. The tree has log n levels. Total: O(n log n).
Time vs Space: Two Separate Bills
Big-O measures two separate resources. Time complexity counts operations. Space complexity counts memory.
Every problem has both. The hash set trick that brought has_duplicate from O(n²) to O(n) time costs O(n) space. Interviewers will ask about both. Always.
Space complexity counts the extra memory your algorithm allocates beyond the input itself. An in-place sort uses O(1) space. Merge sort's auxiliary arrays use O(n) space. A recursion stack n levels deep uses O(n) space even if you're not explicitly storing anything.
def recursive_sum(nums, index=0): if index == len(nums): return 0 return nums[index] + recursive_sum(nums, index + 1) # Time: O(n) -- n recursive calls # Space: O(n) -- call stack depth is n
When you give your complexity analysis in an interview, give both. "O(n) time, O(1) space" is a complete answer. "O(n)" alone leaves half the answer on the table. Interviewers will wait, silently, for you to finish the sentence.
Why Interviewers Care So Much
Big-O is a proxy for whether you think like someone who has shipped code at scale. An algorithm that's "fast enough" locally can become a production outage at 10x traffic.
It also shows up on the rubric. Most major tech companies score problem-solving partly on whether you articulate complexity before and after optimization. A correct solution with no complexity analysis scores lower than a correct solution with "this is O(n²), and here's how we bring it to O(n log n)."
The hiring process can feel like this:

The good news: Big-O is one of those boxes you can actually check.
The practical skill: look at your code, identify the loops, apply the multiply/add rules, then ask whether you can do better. That last question, "can I do better?", is what separates a passing interview from a strong hire.
If you want to practice explaining your complexity analysis under real pressure, SpaceComplexity runs voice-based mock interviews built for exactly that. Typing O(n) into a comment box is one skill. Saying "this is O(n log n) because..." while an interviewer watches is a different one entirely.
The Things Big-O Doesn't Tell You
Big-O ignores constants. Two O(n) algorithms can have a 100x performance difference in practice if one has a constant of 10 and the other has a constant of 0.1. At small n, O(n²) can genuinely outperform O(n log n) because the constant on the faster algorithm is worse. The theory says one thing; the profiler sometimes says another.
Big-O is a worst-case upper bound unless you specify otherwise. Quicksort is O(n log n) on average but O(n²) in the worst case (sorted input with naive pivot selection). Interviewers sometimes ask about average case explicitly. Worth knowing.
Big-O ignores cache effects. Arrays and linked lists are both O(n) for traversal. In practice, arrays are 5 to 10 times faster because sequential memory access exploits CPU cache lines. For a deeper look at why, see Array vs Linked List Performance.
Key Takeaways
- Big-O describes growth rate, not raw speed.
- The six classes in order: O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2^n).
- Sequential loops add. Nested loops multiply.
- Always give both time and space complexity. "O(n)" alone leaves half the answer on the table.
For the formal Bachmann-Landau definition and how O, Theta, and Omega differ, see Big-O Isn't a Tight Bound. For complexity analysis of recursive functions specifically, see Recursion Time Complexity. And for how these classes map to concrete interview problems, Coding Interview Time Complexity covers the five floors you'll see most.
Further Reading
- Wikipedia: Big O notation, formal definition, history, and properties
- MIT 6.006 Introduction to Algorithms, the lecture notes are free and rigorous
- GeeksforGeeks: Analysis of Algorithms, practical examples with code
- CLRS: Introduction to Algorithms, the reference text; chapters 1-3 cover asymptotic notation
- Khan Academy: Asymptotic notation, gentlest on-ramp, with worked examples