Loop Invariants

Week 2, Tuesday (Video)

January 13, 2026

From Monday

We now have two pillars:

  1. Efficiency — How fast? (Big-\(O\))
  2. Correctness — Does it work?

What Big-\(O\) Actually Tells Us

Consider \(T(n) = 3n^2 + 5n + 7\). What happens when \(n\) doubles?

The Doubling Test

Class When \(n\) doubles, time…
\(O(1)\) stays the same
\(O(\log n)\) increases by a constant
\(O(n)\) doubles
\(O(n \log n)\) slightly more than doubles
\(O(n^2)\) quadruples
\(O(2^n)\) squares (!!)

The Practical Classes

\(O(1)\): Constant

arr[0]
d[key]
stack.pop()

“No matter how big the input, same time.”

\(O(\log n)\): Logarithmic

def binary_search(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1

\(O(n)\): Linear

def find_max(arr):
    max_val = arr[0]
    for x in arr:
        if x > max_val:
            max_val = x
    return max_val

\(O(n \log n)\): Linearithmic

sorted(arr)          # Python's built-in
df.sort_values()     # pandas

\(O(n^2)\): Quadratic

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

\(O(2^n)\): Exponential

def all_subsets(arr):
    if not arr:
        return [[]]
    rest = all_subsets(arr[1:])
    return rest + [[arr[0]] + s for s in rest]

Racing Algorithms

The Setup

The Race

What Happened

Worst case: \(\Theta(n^2) \to \Theta(n)\)

The set provides \(O(1)\) lookup.

When Does It Matter?

The Crossover

The Lesson

Small data: write clear code.

Big data: Big-O is destiny.

Galactic Pizza

Two Ways to Compute the Mean

Same Big-\(O\), Different Speed

Both touch every row: \(O(n)\)

But:

  • Vectorized: tiny constants (compiled C)
  • Python loop: large constants (interpreter overhead)