The first time an interviewer asked me "what's the time complexity of that?", I said "O(n)" with total confidence. It was O(n²). I had a loop inside a loop and didn't see it, because I'd learned Big O as a list of symbols and not as a way of counting.
I'd read the explainer posts. I'd seen the chart with the curves bending up and away. I could recite that binary search is O(log n). What I couldn't do was look at my own code and work it out. If that sounds familiar, here's the approach that finally fixed it for me.
Big O is just counting, roughly
Forget the math notation for a minute. Big O answers one question: if the input gets 10 times bigger, how much more work does this code do?
- If the work grows 10 times, it's O(n).
- If it grows 100 times, it's O(n²).
- If it barely grows at all, it's O(1) or O(log n).
That's most of it. You're not timing anything, and constants don't matter. A loop that does three things per item is still O(n), because tripling something that grows in a straight line still gives you a straight line.
Once I started asking "what happens when n doubles?" instead of "which symbol is this?", I stopped guessing.
Learn five shapes, not a chart
There are lots of complexity classes. In day-to-day code and in interviews, you mostly meet five:
-
O(1): a hash map lookup, reading
arr[5], pushing onto a stack. - O(log n): binary search, or anything that cuts the problem in half each step.
- O(n): one pass over the input.
-
O(n log n): a good sort. If you call
.sort(), assume this. - O(n²): a loop inside a loop over the same input. Comparing every pair.
For each one, keep a tiny code example of your own, not one copied from a textbook. Mine for O(n²) is literally the bug from that interview: checking for duplicates with two nested for loops. Mine for O(n) is the fix, the same check with a Set. Having your own example matters more than it sounds. When you see a similar shape later, it's your code you recognize.
Read code from the inside out
This is the habit that does most of the work. When you look at a function, find the innermost thing that runs and ask how many times it runs.
for (const user of users) { // runs n times
for (const order of orders) { // runs m times per user
if (order.userId === user.id) { ... }
}
}
The if runs n × m times, so the whole thing is O(n·m). If users and orders are about the same size, that's effectively O(n²). Now the fix suggests itself: build a map of orders by userId once (O(m)), then loop over users and look each one up (O(n)). Total O(n + m).
Watch out for hidden loops too. array.includes(), indexOf(), slice() and string concatenation in a loop all do work proportional to their input. A single for loop with an includes() inside it is O(n²), even though you only typed one loop. That one catches a lot of people, and it caught me more than once.
Practice on code you already wrote
LeetCode is fine, but there's a better warm-up sitting in your repo. Open a file from last week and label the complexity of three functions in a comment. Then ask whether any of them could be better and whether it would even matter. A function that runs once on a list of 12 items doesn't need fixing, whatever its Big O.
That second question is what interviewers are really after. They want to hear "this is O(n²), and here's how a hash map gets it to O(n), at the cost of O(n) extra memory." The trade-off is the answer, not the symbol.
Space complexity works the same way, by the way. Count what you allocate instead of what you loop over. A new array the size of the input is O(n) space. A few variables is O(1).
Then keep it from fading
Here's where I went wrong for a long time. I'd study Big O hard for a week before interviews, do fine, and then not think about it for months. The next time I needed it, I was back to squinting at nested loops.
What works better is coming back to it on a schedule, a little at a time. After you learn the five shapes, quiz yourself the next day. Then three days later, then a week, then a few weeks. Cover the answer, look at a snippet, and say the complexity out loud before you check. That's spaced repetition, and it's a good fit for this because Big O is a small set of patterns you need to recognize quickly.
I build Recl, and this is a big part of why. Most of what I learned about algorithms came from YouTube walkthroughs and long blog posts, and I'd forget them within a couple of weeks. Now I save the video or article from my phone's share menu or the Chrome extension. Recl writes a summary with the key takeaways, files it under a topic like "Algorithms," and later sends me a recall question about it. When I'm prepping for something, I can also just ask my library a question and get an answer pulled from the things I saved, with the sources.
A notes file and calendar reminders do the same job if you'd rather not use an app. The point is seeing the material again a few times, spaced out, instead of cramming the night before.
A quick self-test
Try these without looking anything up:
- Checking whether a sorted array contains a value, by halving the range each step.
- Finding the largest number in an unsorted array.
- Printing every pair of items in a list.
- Looking up a key in a JavaScript object.
(Answers: O(log n), O(n), O(n²), O(1) on average.)
If you got all four, pick a function you wrote this week and label it. If you missed one, that's the one to write your own example for.
I build Recl, an AI learning app that saves the videos, reels and articles you learn from, summarizes them, sorts them into topics, and uses spaced repetition so you actually remember them.


Top comments (0)