Imagine you have a list of n names. If n = 10, any approach works fine. But if n = 1,000,000, a bad algorithm takes hours while a good one takes milliseconds. Big-O describes this difference.
| Notation | Name | Example | n = 1M → ops | Rating |
|---|---|---|---|---|
| O(1) | Constant | Array index access, HashMap get | 1 operation | ⭐⭐⭐⭐⭐ Best |
| O(log n) | Logarithmic | Binary Search | ~20 operations | ⭐⭐⭐⭐⭐ Excellent |
| O(n) | Linear | Linear Search, array loop | 1,000,000 ops | ⭐⭐⭐⭐ Good |
| O(n log n) | Linearithmic | Merge Sort, Heap Sort | ~20M operations | ⭐⭐⭐ Acceptable |
| O(n²) | Quadratic | Bubble Sort, nested loops | 1 trillion ops 🔥 | ⭐ Avoid |
| O(2ⁿ) | Exponential | Naive recursion (Fibonacci) | Larger than universe 💀 | ❌ Never |
📈 Visualizing Growth Rate (n = 8)
Four algorithms race on the same input. Each step doubles n. Notice that O(log n) barely moves, and O(n²) doesn't just grow — it accelerates away. This picture is the entire reason complexity analysis exists.
📈 The same race as curves
Rule 1: Drop Constants
O(2n) → O(n). Constants don't matter as n → ∞.
Rule 2: Drop Non-Dominants
O(n² + n) → O(n²). The larger term dominates.
Rule 3: Different Inputs
Two separate arrays: O(a + b), NOT O(n). Use different variables!
Rule 4: Loops Multiply
Nested loops on same array: O(n × n) = O(n²).
📖 Read a Problem Statement in 4 Passes
🛠 Brute Force First — then ask the 5 Optimization Questions
Writing the brute force is never wasted: it clarifies the problem, gives you a correctness oracle, and often earns partial credit. Then interrogate it:
Each drill: read the problem, write pseudocode on paper, then reveal the solution. Do NOT look at the solution before attempting!
Find Max in Array
Given an array of integers, find the largest element. Constraint: no built-in max()
max_val = arr[0]
FOR each num in arr:
IF num > max_val:
max_val = num
RETURN max_val
— Time: O(n) | Space: O(1)
Count Even Numbers
Given an array, count how many numbers are even. Pseudocode only.
count = 0
FOR each num in arr:
IF num MOD 2 == 0:
count = count + 1
RETURN count
— Time: O(n) | Space: O(1)
Reverse a String
Reverse the string "hello" → "olleh". No built-in reverse functions.
left = 0, right = len(s) - 1
WHILE left < right:
SWAP s[left] and s[right]
left = left + 1
right = right - 1
RETURN s
— Time: O(n) | Space: O(1)
Check Palindrome
Is "racecar" a palindrome? Write the logic to check any string.
left = 0, right = len(s) - 1
WHILE left < right:
IF s[left] != s[right]:
RETURN False
left++, right--
RETURN True
— Time: O(n) | Space: O(1)
Sum of Digits
Given number 1234, compute 1+2+3+4 = 10. Handle any integer.
total = 0
WHILE n > 0:
digit = n MOD 10
total = total + digit
n = n / 10 (integer division)
RETURN total
— Time: O(digits) | Space: O(1)
Check Anagram
Are "listen" and "silent" anagrams? Two strings with same characters.
IF len(s1) != len(s2): RETURN False
freq = empty map
FOR char in s1: freq[char] += 1
FOR char in s2: freq[char] -= 1
FOR each val in freq:
IF val != 0: RETURN False
RETURN True
— Time: O(n) | Space: O(1)* 26 letters
FizzBuzz Classic
Print 1–100: "Fizz" if divisible by 3, "Buzz" by 5, "FizzBuzz" by both.
FOR i = 1 TO 100:
IF i MOD 15 == 0: PRINT "FizzBuzz"
ELSE IF i MOD 3 == 0: PRINT "Fizz"
ELSE IF i MOD 5 == 0: PRINT "Buzz"
ELSE: PRINT i
Note: check 15 FIRST (both conditions)
Find Duplicates
Given [1,2,3,2,4,3], find all numbers that appear more than once.
seen = empty set
duplicates = empty set
FOR each num in arr:
IF num in seen:
duplicates.add(num)
ELSE:
seen.add(num)
RETURN duplicates
— Time: O(n) | Space: O(n)
Fibonacci Sequence
Generate first n Fibonacci numbers. F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2).
a = 0, b = 1
FOR i = 0 TO n:
PRINT a
next = a + b
a = b
b = next
Note: iterative is O(n), recursive naive is O(2ⁿ)!
Binary Search
Given sorted array [1,3,5,7,9,11], find index of target=7. O(log n).
left = 0, right = len(arr) - 1
WHILE left <= right:
mid = (left + right) / 2
IF arr[mid] == target: RETURN mid
ELSE IF arr[mid] < target: left = mid + 1
ELSE: right = mid - 1
RETURN -1 (not found)
— Time: O(log n) | Space: O(1)
Second Largest Element
Find the second largest value in an array in one pass. Handle duplicates ([5,5,3] → 3).
first = -infinity, second = -infinity
FOR each num in arr:
IF num > first:
second = first
first = num
ELSE IF num < first AND num > second:
second = num
RETURN second
— Time: O(n) | Space: O(1)
Merge Two Sorted Arrays
Given two sorted arrays, produce one sorted array. This is the heart of merge sort.
i = 0, j = 0, result = []
WHILE i < len(a) AND j < len(b):
IF a[i] <= b[j]:
APPEND a[i] to result, i++
ELSE:
APPEND b[j] to result, j++
APPEND remaining of a, then remaining of b
RETURN result
— Time: O(n + m) | Space: O(n + m)
First Non-Repeating Character
In "swiss", the first character that appears exactly once is 'w'. Find it for any string.
counts = empty map
FOR each ch in s: // pass 1: count
counts[ch] = counts[ch] + 1
FOR each ch in s: // pass 2: first with count 1
IF counts[ch] == 1:
RETURN ch
RETURN none
— Time: O(n) | Space: O(1) (≤ 26 keys)
Max Sum of Any 3 Consecutive Elements
Find the largest sum over all windows of 3 consecutive elements — without re-adding each window.
window = arr[0] + arr[1] + arr[2]
best = window
FOR i from 3 to len(arr) - 1:
window = window + arr[i] - arr[i-3] // slide!
best = MAX(best, window)
RETURN best
— Time: O(n) | Space: O(1)
Naive re-adding = O(3n); sliding keeps it one op per step.