Theta Notation Explained- Your Complete Big-O Notation Guide

What Theta Notation Actually Is

Theta notation (Θ) describes the tight bound on an algorithm's runtime. It tells you both the upper limit and the lower limit. When you say f(n) = Θ(g(n)), you're saying the running time grows exactly like g(n) — not faster, not slower.

Most developers learn Big-O first and stop there. That's a problem. Big-O only gives you the worst case. Theta gives you the reality.

Theta vs Big-O vs Big-Omega

These three notations answer different questions:

Think of it like speed limits. Big-O is the maximum speed limit sign. Big-Omega is the minimum speed limit sign. Theta is the actual speed everyone's doing.

The Formal Definition (Skip If You Want)

f(n) = Θ(g(n)) when there exist positive constants c1, c2, and n₀ such that:

0 ≤ c₁g(n) ≤ f(n) ≤ c₂g(n) for all n ≥ n₀

Translation: the function f(n) is sandwiched between two multiples of g(n) once n gets large enough. That's the tight bound.

Common Theta Complexities

Here are the Theta notations you'll encounter most, from fastest to slowest:

Comparison Table: Theta vs Big-O vs Big-Omega

Notation Meaning Use Case Example
Θ(1) Tight bound = constant Array access arr[0]
Θ(n) Tight bound = linear Single traversal Linear search
O(n) Upper bound ≤ n Worst case analysis Quick sort worst case
Ω(n) Lower bound ≥ n Best case analysis Linear search best case
Θ(n²) Tight bound = quadratic Nested iterations Bubble sort

How to Determine Theta Notation

Step 1: Count the Operations

Count how many basic operations execute as a function of input size n. Don't count lines — count actual operations that scale with input.

Step 2: Find the Dominant Term

Drop all constants and lower-order terms. If your runtime is 3n² + 5n + 12, the dominant term is n². That's your Theta.

Step 3: Verify the Tight Bound

Ask yourself: "Is this the best I can do?" If you're describing the exact growth rate, use Θ. If you're only describing worst case, use O.

Examples in Code

Example 1: Finding an Element

// Linear search
function findElement(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}

Best case: O(1) — found at index 0. Worst case: O(n) — not found or at end. Theta(n) — because on average, you check half the elements, which is still linear.

Example 2: Binary Search

function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  while (left <= right) {
    let mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    else if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  return -1;
}

Each iteration halves the search space. Theta(log n). Every case — best, worst, average — is the same.

Example 3: Nested Loops

function printPairs(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length; j++) {
      console.log(arr[i], arr[j]);
    }
  }
}

Outer loop runs n times. Inner loop runs n times for each iteration. That's n × n = n² operations. Theta(n²).

When to Use Theta (And When Not To)

Use Theta when:

Use Big-O when:

Common Mistakes

1. Confusing O with Θ: Big-O is an upper bound. Theta is a tight bound. Not all O(n) algorithms are Θ(n).

2. Ignoring constants: In practice, n² with a tiny constant might beat n with a massive constant. Theta doesn't capture this.

3. Forgetting best case vs worst case: Quicksort is O(n²) worst case but Θ(n log n) on average. Know which one matters for your use case.

Bottom Line

Theta notation gives you the tight bound. Big-O gives you the ceiling. If you only learn one, learn Big-O — it's what everyone expects in interviews and production code. But if you're doing rigorous analysis, Theta is what you actually need.

Don't overthink this. Count your operations, drop the constants, and pick the right notation for your context.