Big-O notation describes how runtime or memory grows as input size n increases. We ignore constants and focus on dominant terms—same idea you glimpsed when comparing Python loops to NumPy vectorization.
Common complexities (slowest to fastest growth)
- O(1) — constant: index into array
- O(log n) — halving: binary search
- O(n) — linear: single loop over n items
- O(n log n) — efficient sorts, many divide-and-conquer algorithms
- O(n²) — nested loops over n
- O(2ⁿ) — exponential; brute-force subsets (avoid at large n)
Rules of thumb
- Drop constants: O(3n) → O(n)
- Keep dominant term: O(n² + n) → O(n²)
- Different inputs? O(a + b) when two arrays of different sizes
Count operations
#include
int main() {
int n = 8;
int ops = 0;
for (int i = 0; i < n; ++i) ops++; // O(n)
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) ops++; // O(n^2)
std::cout << "ops ~ n + n^2 = " << ops << "\n";
return 0;
}
Important interview questions and answers
- Q: Does Big-O measure exact seconds?
A: No—it describes growth rate; hardware and constants still affect wall-clock time. - Q: Best vs worst vs average?
A: Interviews often mean worst-case unless stated; hash maps average O(1) with rare O(n) worst case.
Self-check
- Order O(1), O(n), O(n²) from fastest growing to slowest.
- Why drop the constant in O(3n)?
Tip: Drop constants and lower-order terms—interviewers want dominant growth.
Interview prep
- Big-O purpose?
Describes growth rate as n increases; ignores constants.
- Common orders?
O(1), O(log n), O(n), O(n log n), O(n²), exponential.
- Average vs worst?
Clarify which case—hash map average O(1), worst O(n) with collisions.