Topzee logo
Open menu
DSA Interview Prep

Big O Notation for Beginners: Explained Simply With Code

Big O notation explained in plain language with real code examples, for developers who've heard the term but never really got it.

Topzee4 min read
Abstract Big O notation cover with chart-like curves and Topzee dark blue technical styling.

Big O notation for beginners can sound more complicated than it needs to be. At its core, Big O is a way to describe how your code scales as the input grows. It is not about measuring exact milliseconds. It is about asking, “What happens when this list has 10 items, 10,000 items, or 10 million items?”

That question matters in interviews because interviewers want to see how you reason about tradeoffs, not only whether your code works for the tiny sample input.

Big O Notation for Beginners: Why It Exists

Imagine two functions that both work for a list of 10 users. One checks each user once. The other compares every user with every other user. With 10 users, both may feel instant. With 100,000 users, the second approach can become unusable.

Big O gives us a shared language for that growth.

It ignores hardware, network speed, and language details. It focuses on the broad shape of the work.

O(1): Constant Time

O(1) means the work does not grow with the input size.

function firstItem<T>(items: T[]): T | undefined {
  return items[0];
}

Whether the array has 5 items or 5 million items, this function reads one position.

Common O(1) operations include:

  • Reading an array by index
  • Adding to the end of many dynamic arrays
  • Looking up a value in a hash map by key on average

The interview clue is direct access. If you do not loop or recurse based on input size, it may be O(1).

O(n): Linear Time

O(n) means the work grows in proportion to the input.

function containsUser(users: string[], target: string): boolean {
  for (const user of users) {
    if (user === target) {
      return true;
    }
  }

  return false;
}

In the worst case, the target is at the end or not present, so the function checks every item.

If the list doubles, the possible work roughly doubles. That is linear time.

O(n^2): Quadratic Time

O(n^2) often appears when you nest loops over the same input.

function hasDuplicateSlow(items: string[]): boolean {
  for (let i = 0; i < items.length; i += 1) {
    for (let j = i + 1; j < items.length; j += 1) {
      if (items[i] === items[j]) {
        return true;
      }
    }
  }

  return false;
}

For every item, the function compares against many other items. As input grows, the number of comparisons grows quickly.

You can usually improve this with a Set:

function hasDuplicateFast(items: string[]): boolean {
  const seen = new Set<string>();

  for (const item of items) {
    if (seen.has(item)) {
      return true;
    }
    seen.add(item);
  }

  return false;
}

This version is O(n) on average because each item is processed once.

O(log n): Logarithmic Time

O(log n) usually appears when you cut the problem size down repeatedly.

Binary search is the classic example:

function binarySearch(nums: number[], target: number): number {
  let left = 0;
  let right = nums.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (nums[mid] === target) return mid;
    if (nums[mid] < target) left = mid + 1;
    else right = mid - 1;
  }

  return -1;
}

The input must be sorted. Each step eliminates half the remaining search space.

That is why binary search can handle very large lists with surprisingly few checks.

A Simple Intuition

Think of finding a name in a printed dictionary. If you start at page one and read every entry, that is linear. If you open near the middle and keep cutting the search area in half, that is logarithmic.

Big O is about the strategy, not the stopwatch.

How to Spot Complexity in Your Code

Start by finding loops and recursion.

One loop over the input is often O(n). Two separate loops one after another are still O(n), because constants are ignored.

for (const item of items) {
  console.log(item);
}

for (const item of items) {
  console.log(item.toUpperCase());
}

This is O(2n), which simplifies to O(n).

Nested loops over the same input are often O(n^2). A loop that halves the search space is often O(log n). Sorting is often O(n log n), depending on the algorithm.

Practice Tip

Take a function from an app you have built. Find every loop, every nested loop, and every data structure lookup. Ask what happens if the input becomes 10 times larger.

That habit makes Big O less abstract. You stop memorizing labels and start seeing performance shapes in everyday code.

If you are using DSA prep to become a stronger product engineer, keep practicing with small explanations you can say out loud. That skill transfers directly into technical conversations.