Skip to content

Beginner: foundations · Thinking in Big-O · topic 2 of 61 · 35 min

Big-O time complexity

Explanation

Big-O describes how the number of steps your code takes grows as the input grows. You drop constants and smaller terms, so 3n + 5 steps is O(n). Loops one after another add up; loops inside loops multiply. Knowing the common classes, from O(1) to O(n!), tells you before you run anything whether an idea is fast enough.

Why count steps, not seconds

The same program takes different times on a new laptop and an old phone, so seconds are a poor way to compare ideas. Instead we count basic steps: one comparison, one addition, one read from a list. We call the input size n (for example, the number of items in a list). Time complexity is how the number of steps grows as n grows.

Big-O notation writes that growth in a short form. O(n), read "order n", means the steps grow in proportion to n: double the input and you roughly double the work. Big-O usually describes the worst case, the input that makes your code work hardest.

Drop constants and smaller terms

If your code takes 3n + 5 steps, we write O(n). If it takes n² + 100n steps, we write O(n²). The reason is that for large n the biggest term wins: with n = 1,000,000, n² is a million million while 100n is only a hundred million. Constants like 3 depend on the machine and language; the shape of the growth does not.

python
def first_item(nums):          # O(1): one step, whatever n is
    return nums[0]

def total(nums):               # O(n): one step per item
    s = 0
    for x in nums:
        s += x
    return s

def all_pairs(nums):           # O(n²): n steps for each of n items
    pairs = []
    for a in nums:
        for b in nums:
            pairs.append((a, b))
    return pairs

print(total([1, 2, 3]))        # Output: 6
print(len(all_pairs([1, 2, 3])))  # Output: 9
Three items give 3 steps for total and 3 × 3 = 9 pairs.

The common classes

Big-ONamen = 10n = 1,000n = 10⁶Typical example
O(1)constant111Reading nums[i], a dict lookup
O(log n)logarithmic≈ 3≈ 10≈ 20Binary search
O(n)linear101,00010⁶One loop over the list
O(n log n)linearithmic≈ 33≈ 10,000≈ 2 × 10⁷Good sorting (merge sort, sorted())
O(n²)quadratic10010⁶10¹²Checking every pair
O(2ⁿ)exponential1,024≈ 10³⁰¹impossibleTrying every subset
O(n!)factorial3,628,800impossibleimpossibleTrying every ordering

A rough rule of thumb: a computer does about 10⁸ simple operations per second in a fast compiled language like C++, and Python is often 10 to 50 times slower. So with n = 10⁶, an O(n log n) idea finishes in well under a second, while an O(n²) idea needs about 10¹² steps, which is hours. Treat these numbers as rough guides, not exact timings.

Tip: Read the input limits in a problem. n up to 10⁵ or 10⁶ usually means O(n) or O(n log n) is expected. n up to about 20 hints that O(2ⁿ) is allowed.

Sequential versus nested loops

Two loops one after another ADD: O(n) + O(n) = O(2n), which is still O(n). A loop inside a loop MULTIPLIES: n steps of the outer loop, each doing n steps, is O(n²). If the two loops run over different inputs of sizes n and m, the costs are O(n + m) and O(n × m); do not merge them into one letter.

python
def has_duplicate_slow(nums):
    for i in range(len(nums)):
        for j in range(i + 1, len(nums)):
            if nums[i] == nums[j]:
                return True
    return False

def has_duplicate_fast(nums):
    seen = set()
    for x in nums:
        if x in seen:          # a set lookup is O(1) on average
            return True
        seen.add(x)
    return False

print(has_duplicate_slow([3, 1, 3]), has_duplicate_fast([3, 1, 3]))  # Output: True True
The inner loop of the slow version runs n − 1, n − 2, … 1 times, about n²/2 steps: still O(n²). The set version is O(n) time and O(n) extra space.

Common mistakes

  • Missing hidden loops. x in a_list, a_list.index(x) and a_list.count(x) each scan the whole list, so using them inside a loop gives O(n²). Fix: use a set or dict for lookups.
  • Keeping constants: writing O(2n) or O(n/2). Fix: both are O(n).
  • Merging different inputs: a loop over n users inside a loop over m products is O(n × m), not O(n²). Fix: give each input its own letter.
  • Thinking every "two loops" is O(n²). Fix: check whether the loops are nested or one after the other, and how far each one runs.
  • Worrying about the base of a logarithm. Fix: log₂ n and log₁₀ n differ only by a constant, so both are just O(log n).

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Big-O time complexity · 1/8

Big-O time complexity

This lesson teaches Big-O, the language every interviewer uses to talk about speed.

Prefer a video by a teacher? Find free videos on “big o notation time complexity explained for beginners” on YouTube ↗

In real life: Matching payments to orders

An online shop receives a file of UPI payment confirmations and has a list of order IDs. A first version checks each payment against the whole order list: O(n × m). With thousands of orders this is fine, but with lakhs of orders a day the nightly job crawls. Putting the order IDs in a set first makes each check O(1) on average, so the job becomes O(n + m) and finishes in seconds. Choosing the data structure changed the Big-O, not just the speed.

python
orders = ["A101", "A102", "A103", "A104"]
payments = ["A103", "A999", "A101"]

order_set = set(orders)                      # O(m) once
unmatched = [p for p in payments if p not in order_set]   # O(n)
print(unmatched)
Shows ['A999']: a payment with no matching order, found in O(n + m).

Practice (0/3 done)

Task 1 · Code · Python

The starter shows a slow O(n²) duplicate check in a comment. Write has_duplicate(nums) that returns True if any value appears at least twice, else False, in O(n) time using a set. Example: has_duplicate([1, 2, 3, 1]) returns True.

Task 2 · Code · Python

Write count_pairs(nums, k) that returns how many pairs of positions (i, j) with i < j have nums[i] + nums[j] == k. Use ONE pass and a dictionary of counts, so it is O(n) time. Example: count_pairs([1, 5, 7, -1], 6) returns 2 (1 + 5 and 7 + -1).

Task 3 · Question

What is the time complexity of this code? for i in range(n): j = 1 while j < n: j *= 2

Quick quiz

Question 1

1.Code takes 4n² + 10n + 7 steps. What is its Big-O?

Question 2

2.Two separate loops over the same list of n items, one after the other. What is the cost?

Question 3

3.For each of n students you loop over m subjects. What is the cost?

Question 4

4.Inside a loop over n items you write if x in my_list, where my_list also has n items. What is the total cost?

Question 5

5.n can be up to 10⁶. Which approach is realistic?

Read more (free)

Before this, learn

This topic builds on these. If something here feels new, open them first.

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Code takes 4n² + 10n + 7 steps. What is its Big-O?

Answer: O(n²)

Drop the constant 4 and the smaller terms 10n and 7.

Two separate loops over the same list of n items, one after the other. What is the cost?

Answer: O(n)

Loops one after another add: n + n = 2n, which is O(n).

For each of n students you loop over m subjects. What is the cost?

Answer: O(n × m)

Nested loops over different inputs multiply, and each input keeps its own letter.

Inside a loop over n items you write if x in my_list, where my_list also has n items. What is the total cost?

Answer: O(n²)

x in a list scans the list, O(n), and it runs n times: O(n²). A set would make it O(n).

n can be up to 10⁶. Which approach is realistic?

Answer: O(n log n)

About 2 × 10⁷ steps is fast; 10¹² steps (n²) would take hours.

A loop over n items that calls array.includes on another n items is…Related

Answer: O(n²)

includes is itself a loop, so the total is n × n.

From Performance thinking and Big-O

A recursive function calls itself n levels deep and makes no lists. What is its space complexity?Related

Answer: O(n)

Each waiting call keeps a frame on the call stack, so n frames means O(n) space.

From Space complexity and amortised cost

A loop inside a loop, both over the same list of n items, is usually...Related

Answer: O(n^2)

For each of the n items, the inner loop does n steps: n times n.

From Big-O and searching

Linear search for a target that is the first item takes one step. Which case is that?Related

Answer: Best case

The input that makes the code do the least work is the best case.

From Best, average and worst case; analysing loops and recursion

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Thinking in Big-O” before its exam: Space complexity and amortised cost, Best, average and worst case; analysing loops and recursion, The real cost of Python and JavaScript built-ins.
  2. Module 1 exam: Thinking in Big-O · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Arrays and strings. 61 topics left in the course before the final exam.

← Previous: What DSA is, and how to learn it