Skip to main content
Foundations7 min read

Big-O Notation

How to measure whether code is fast or slow, before you ever run it.

Imagine two programs that both find a name in a phone book. One flips through every page from the front; the other opens to the middle, decides which half the name is in, and repeats. Both give the right answer, but with a million entries, one takes a million steps and the other takes about twenty. Big-O notation is the language we use to describe that difference without running either program.

Interviewers care about Big-O because it predicts how your code behaves when the input gets huge. A solution that feels instant on ten items can take minutes on ten million. Learning to read and state Big-O is the single most transferable skill in interview prep: every data structure and algorithm you learn from here on is described in these terms.

Counting steps, not seconds

Big-O does not measure time in seconds. Seconds depend on your laptop, your compiler, and whether Spotify is running. Instead, it counts how the number of basic steps grows as the input size grows. We call the input size n: the length of an array, the number of characters in a string, the number of users in a list.

Here is the key mental shift: we only care about the growth trend, not exact counts. If one algorithm takes 3n + 5 steps and another takes n steps, both double their work when n doubles, so both are O(n), pronounced "order n" or "linear time". Constants and small terms get dropped because for large n they stop mattering. What matters is the shape of the curve: does the work grow in a straight line, a gentle curve, or an explosion?

The common complexity classes

You will meet the same handful of growth rates over and over, from fastest to slowest. O(1), constant time, means the work does not depend on n at all, like grabbing an array element by index. O(log n), logarithmic time, means the work grows very slowly because each step cuts the problem in half, that is the phone-book trick, formally called binary search. O(n), linear time, means you touch each element once, like a simple loop. O(n log n) is the cost of good sorting algorithms. O(n squared), quadratic time, usually means a loop inside a loop. Every element compared against every other element. Beyond that live O(2 to the n) and worse, which only work for tiny inputs.

To feel the difference, take n = 1,000,000. O(log n) is about 20 steps. O(n) is a million. O(n log n) is about 20 million, still fine. O(n squared) is a trillion steps, which is minutes to hours. In an interview, moving a solution from O(n squared) to O(n) or O(n log n) is often the whole point of the question.

Java
int[] nums = {4, 8, 15, 16, 23, 42};

int first = nums[0];

int sum = 0;
for (int x : nums) {
    sum += x;
}

int pairCount = 0;
for (int i = 0; i < nums.length; i++) {
    for (int j = i + 1; j < nums.length; j++) {
        pairCount++;
    }
}

How to find the Big-O of your code

Reading complexity off code is mostly pattern matching. A single loop over n elements is O(n). Two loops one after another are O(n) + O(n), which we still call O(n). Remember, constants are dropped. A loop nested inside another loop, where both run n times, multiplies: O(n squared). A loop that halves its range each iteration, like binary search, is O(log n). Calling an O(n) helper inside an O(n) loop gives O(n squared), so watch out for hidden work. Methods like contains on a list are loops in disguise.

One more convention: Big-O usually describes the worst case. Searching an array for a value might get lucky and find it at index 0, but we say the search is O(n) because in the worst case we check everything. When someone asks "what is the complexity?", give the worst case unless they ask otherwise.

Java
boolean contains(int[] nums, int target) {
    for (int x : nums) {
        if (x == target) {
            return true;
        }
    }
    return false;
}

Space complexity and the time-space trade

Big-O also measures memory. Space complexity counts the extra memory your algorithm allocates as n grows, not counting the input itself. A method that uses a few int variables is O(1) space no matter how big the array is. A method that copies the array, or builds a hash map with one entry per element, is O(n) space.

Many classic interview optimizations are a trade: spend memory to save time. A nested-loop duplicate check is O(n squared) time and O(1) space; adding each element to a set as you go is O(n) time and O(n) space. Being able to name both costs ("this is O(n) time, O(n) space") is exactly what interviewers listen for.

With this vocabulary in hand, you are ready to meet your first real data structure: the array, whose superpower is O(1) access to any element.

key takeaways
Big-O describes how the number of steps grows as input size n grows, ignoring constants and machine speed.
The classes to memorize, fastest to slowest, are O(1), O(log n), O(n), O(n log n), and O(n squared).
A single loop is O(n), nested loops are O(n squared), and repeatedly halving the input is O(log n).
Big-O states the worst case by default, and it applies to memory (space complexity) as well as time.
Many optimizations trade extra space, like a hash set, for dramatically less time.

Frequently asked

Why do we drop constants. Surely 2n steps is slower than n steps?

Yes, 2n is slower than n, but both double when the input doubles, so they scale the same way. Big-O is about scaling behavior, because constant factors depend on hardware and language details that vary machine to machine. When two algorithms are in different classes, like O(n) versus O(n squared), the class difference dwarfs any constant for large inputs.

Is an O(n squared) solution always wrong in an interview?

No. It is often the right first step: state the brute-force solution, give its complexity, then improve it out loud. For small constraints, say n up to 1,000, an O(n squared) solution may even be perfectly acceptable. Trouble starts when n reaches the hundreds of thousands and quadratic work becomes billions of steps.

What is the difference between time complexity and space complexity?

Time complexity counts the steps an algorithm performs; space complexity counts the extra memory it allocates beyond the input. They are independent: an algorithm can be fast but memory-hungry, or slow but tiny. Interviewers usually expect you to state both.