“As soon as an Analytic Engine exists, it will necessarily guide the future course of the science. Whenever any result is sought by its aid, the question will arise—By what course of calculations can these results be arrived at by the machine in the shortest time?
”
–Charles Babbage (1864)
![]() |
![]() |
Deterministic Turing Machine: simple and idealistic model

Running time: number of steps
Memory: number of tape cells utilized
Caveat: No random access of memory
Word RAM

Running time: number of primitive operations
Memory: Number of memory cells utilized
Caveat: At times, need more refined model (e.g., multiply \(n\)-bit ints)
Brute Force: For many nontrivial problems, there is a natural brute-force search algorithm that checks every possible solution.

Ex: Stable matching problem: test all \(n!\) perfect matchings for stability
Desirable scaling property: When the input size doubles, the algorithm should slow down by at most some constant factor \(C\)
An algorithm is poly-time if the above scaling property holds
There exist constants \(a > 0\) and \(b > 0\) such that, for every input of size \(n\), the running time of the algorithm is bounded above by \(a n^b\) primitive computational steps.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
We say that an algorithm is efficient if it has a polynomial running time
Theory: Definition is (relatively) insensitive to model of computation
Practice: It really works!

Exceptions: Some poly-time algorithms in the wild have galactic constants and/or huge exponents
Q. Which would you prefer:
Worst Case: running time guarantee for any input of size \(n\)
Exceptions: Some exponential-time algorithms are used widely in practice, because the worst-case instances don't arise.
![]() |
![]() |
![]() |
Probabilistic: Expected running time of a randomized algorithm
Amortized: Worst-case running time for any sequence of \(n\) operations
Also: Average-case analysis, smoothed analysis, competitive analysis, ...

Upper Bounds: \(f(n)\) is \(O(g(n))\) if there exist constants \(c > 0\) and \(n_0 \geq 0\) such that \(0 \leq f(n) \leq c \cdot g(n)\) for all \(n \geq n_0\).
Ex: \(f(n) = 32 n^2 + 17 n + 1\)
Typical usage: Insertion sort makes \(O(n^2)\) compares to sort \(n\) elements.
Let \(f(n) = 3n^2 + 17n \log_2 n + 1000\).
Which of the following are true?
One-way "equality": \(O(g(n))\) is a set of functions, but computer scientists often write \(f(n) = O(g(n))\) instead of \(f(n) \in O(g(n))\)
Ex: Consider \(g_1(n) = 5n^3\) and \(g_2(n) = 3n^2\).
Domain and Codomain: \(f\) and \(g\) are real-valued functions
Bottom line: OK to abuse notation in this way; not OK to misuse it.
| Reflexivity | \(f\) is \(O(f)\) |
| Constants | If \(f\) is \(O(g)\) and \(c > 0\), then \(c f\) is \(O(g)\) |
| Products | If \(f_1\) is \(O(g_1)\) and \(f_2\) is \(O(g_2)\), then \(f_1f_2\) is \(O(g_1g_2)\) (proof) |
| Sums | If \(f_1\) is \(O(g_1)\) and \(f_2\) is \(O(g_2)\), then \(f_1 + f_2\) is \(O(\max (g_1, g_2))\) (ignore lower-order terms) |
| Transitivity | If \(f\) is \(O(g)\) and \(g\) is \(O(h)\), then \(f\) is \(O(h)\). |
Examples:

Lower Bounds: \(f(n)\) is \(\Omega(g(n))\) if there exists constants \(c > 0\) and \(n_0 \geq 0\) such that \(f(n) \geq c \cdot g(n) \geq 0\) for all \(n \geq n_0\).
Ex: \(f(n) = 32n^2 + 17n + 1\).
Typical usage: Any compare-based sorting algorithm requires \(\Omega(n \log n)\) compares in the worst case.
Vacuous statement: Any compare-based sorting algorithm requires at least \(O(n \log n)\) compares in the worst case (upper bound (\(O\)) is lower bound ("at least")?)
Which is an equivalent definition of big Omega notation?
Assume: \(n \in \mathbb{Z}\)
\(f(n)\) is \(\Omega(g(n))\) iff \(g(n)\) is \(O(f(n))\).
\(f(n)\) is \(\Omega(g(n))\) iff there exists constant \(c>0\) such that \(f(n) \geq c \cdot g(n) \geq 0\) for infinitely many \(n\).
Both A and B.
Neither A nor B.

Tight bounds: \(f(n)\) is \(\Theta(g(n))\) if there exist constants \(c_1>0\), \(c_2>0\), and \(n_0\geq 0\) such that \(0 \leq c_1 g(n) \leq f(n) \leq c_2 g(n)\) for all \(n \geq n_0\).
Ex: \(f(n) = 32n^2 + 17n + 1\)
Typical usage: Mergesort makes \(\Theta(n \log n)\) compares to sort \(n\) elements (between \(\frac{1}{2} n \log_2 n\) and \(n \log_2 n\))
Which is an equivalent definition of big Theta notation?
\(f(n)\) is \(\Theta(g(n))\) iff \(f(n)\) is both \(O(g(n))\) and \(\Omega(g(n))\).
\(f(n)\) is \(\Theta(g(n))\) iff \(\displaystyle\lim_{n\rightarrow\infty} \frac{f(n)}{g(n)} = c\) for some constant \(0 < c < \infty\).
Both A and B.
Neither A nor B.
Proposition: If \(\displaystyle\lim_{n\rightarrow\infty} \frac{f(n)}{g(n)} = c\) for some constant \(0 < c < \infty\) then \(f(n)\) is \(\Theta(g(n))\).
Pf:
Propositions:
If \(\displaystyle\lim_{n\rightarrow\infty} \frac{f(n)}{g(n)} = 0\), then \(f(n)\) is \(O(g(n))\) but not \(\Omega(g(n))\)
If \(\displaystyle\lim_{n\rightarrow\infty} \frac{f(n)}{g(n)} = \infty\), then \(f(n)\) is \(\Omega(g(n))\) but not \(O(g(n))\)
Polynomials: Let \(f(n) = a_0 + a_1n + \ldots + a_dn^d\) with \(a_d>0\). Then, \(f(n)\) is \(\Theta(n^d)\).
Pf:
\[ \lim_{n\rightarrow\infty} \frac{a_0 + a_1n + \ldots + a_dn^d}{n^d} = a_d > 0 \]
Logarithms: \(\log_a n\) is \(\Theta(\log_b n)\) for every \(a>1\) and every \(b > 1\). (no need to specify base assuming it is a constant)
Pf:
\[ \frac{\log_a n}{\log_b n} = \frac{1}{\log_b a}\]
Logarithms and Polynomials: \(\log_a n\) is \(O(n^d)\) for every \(a > 0\) and every \(d > 0\)
Pf:
\[ \lim_{n\rightarrow\infty} \frac{\log_a n}{n^d} = 0 \]
Exponentials and Polynomials: \(n^d\) is \(O(r^n)\) for every \(r>1\) and every \(d>0\).
Pf:
\[ \lim_{n\rightarrow\infty} \frac{n^d}{r^n} = 0 \]
Factorials: \(n!\) is \(2^{\Theta(n \log n)}\).
\[ n! \sim \sqrt{2\pi n} \left(\frac{n}{e}\right)^n \]
Upper Bounds: \(f(m,n)\) is \(O(g(m,n))\) if there exist constants \(c>0\), \(m_0\geq0\), and \(n_0\geq 0\) such that \(0 \leq f(m,n) \leq c \cdot g(m,n)\) for all \(n \geq n_0\) and \(m \geq m_0\).
Ex: \(f(m,n) = 32mn^2 + 17mn + 32n^3\)
Typical usage: Breadth-first search takes \(O(m+n)\) time to find a shortest path from \(s\) to \(t\) in a digraph with \(n\) nodes and \(m\) edges.
Goal: Implement Gale-Shapley to run in \(O(n^2)\) time
// Gale-Shapley (preference lists for hospitals and students)
Initialize M to empty matching
While some hospital h is unmatched and hasn't proposed to every student:
s <- first student on h's list to whom h has not yet proposed
If s is unmatched
Add h-s to matching M
Else If s prefers h to current partner h'
Replace h'-s with h-s in matching M
Else
s rejects h
Return stable matching M
Goal: Implement Gale-Shapley to run in \(O(n^2)\) time
Representing hospitals and students: Index hospitals and students 1, ..., n
Representing the matching:
students[h] and hospitals[s]students[h]=0 for all h and hospitals[s]=0 for all s to designate that all hospitals and students are unmatchedstudents[h] = s and hospitals[s] = hKey: Can add/remove a pair from matching in \(O(1)\) time
Goal: Implement Gale-Shapley to run in \(O(n^2)\) time
Representing the matching:
students[h] and hospitals[s]Key: Can find an unmatched hospital in \(O(1)\) time
Hospital makes a proposal

Key: Can make a proposal in \(O(1)\) time.
Student accepts/rejects a proposal
| 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | 8th | |
|---|---|---|---|---|---|---|---|---|
pref[]: |
8 | 3 | 7 | 1 | 4 | 5 | 6 | 2 |
for i = 1 to n
inverse[pref[i]] = i
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
inverse[] |
4th | 8th | 2nd | 5th | 6th | 7th | 3rd | 1st |
Key: After \(\Theta(n^2)\) preprocessing time (to create the \(n\) ranking arrays, each of length \(n\)), it takes \(O(1)\) time to accept/reject a proposal.
Theorem: We can implement Gale-Shapley to run in \(O(n^2)\) time.
Pf:
Theorem: In the worst case, any algorithm to find a stable matching must query the hospital's preference list \(\Omega(n^2)\) times.
Constant time: Running time is \(O(1)\) (bounded by a constant, which does not depend on input size \(n\))
Examples:
Linear time: Running time is \(O(n)\)
Merge two sorted lists: Combine two sorted linked lists \(A = a_1, a_2, \ldots, a_n\) and \(B = b_1, b_2, \ldots, b_n\) into a sorted whole.
\(O(n)\) algorithm: Merge in Mergesort.

i <- 1; j <- 1.
While both lists are nonempty:
If a[i] <= b[j]
Append a[i] to output list and increment i
Else
Append b[j] to output list and increment j
Append remaining elements from nonempty list to output list
Target-Sum: Given a sorted array of \(n\) distinct integers and an integer \(T\), find two that sum exactly \(T\).
Logarithmic time: Running time is \(O(\log n)\)
Search in a sorted array: Given a sorted array \(A\) of \(n\) numbers, is a given number \(x\) in the array?
\(O(\log n)\) algorithm: Binary search
Search-in-Sorted-Rotated-Array: Given a rotated sorted array of \(n\) distinct integers and an element \(x\), determine if \(x\) is in the array.
Linearithmic time: Running time is \(O(n \log n)\)
Sorting: Given an array of \(n\) elements, rearrange them in ascending order.
\(O(n \log n)\) algorithm: Mergesort

Largest-Empty-Interval: Given \(n\) timestamps \(x_1, \ldots, x_n\) on which copies of a file arrive at a server, what is largest interval when no copies of file arrive?
Quadratic time: Running time is \(O(n^2)\)
Closest pair of points: Given a list of \(n\) points in the plane \((x_1,y_1), \ldots, (x_n,y_n)\), find the pair that is closest to each other.
\(O(n^2)\) algorithm: Enumerate all pairs of points.
min <- infty
For i = 1 to n
For j = i+1 to n
d <- (x[i] - x[j])^2 + (y[i] - y[j])^2
If d < min
min <- d
Remark on Closest Pair: \(\Omega(n^2)\) seems inevitable, but this is just an illusion (see section 5.4 Finding the Closest Pair of Points)
Cubic time: Running time is \(O(n^3)\)
3-Sum: Given an array of \(n\) distinct ints, find three that sum to 0
\(O(n^3)\) algorithm: Enumerate all triples.
For i = 1 to n
For j = i+1 to n
For k = j+1 to n
If a[i] + a[j] + a[k] = 0
Return (a[i], a[j], a[k])
Remark on 3-Sum: \(\Omega(n^3)\) seems inevitable, but \(O(n^2)\) is not hard.
3-Sum: Given an array of \(n\) distinct ints, find three that sum to 0
Polynomial time: Running time is \(O(n^k)\) for some constant \(k > 0\)
Independent set of size \(k\): Given a graph, find \(k\) nodes (\(k\) is constant) such that no two are joined by an edge.
\(O(n^k)\) algorithm: Enumerate all subsets of \(k\) nodes.
Foreach subset S of k nodes: // O(n^k/k!) reps
Check whether S is an independent set. // k^2
If S is an independent set
Return S
Exponential time: Running time is \(O(2^{n^k})\) for some constant \(k>0\)
Independent set: Given a graph, find independent set of max cardinality
\(O(n^2 2^n)\) algorithm: Enumerate all subsets
S* <- empty // constant
Foreach subset S of nodes: // 2^n reps
Check whether S is an independent set // n^2
If S is an independent set AND |S| > |S*|
S* <- S
Return S*
Which is an equivalent definition of exponential time?
\(O(2^n)\)
\(O(2^{cn})\) for some constant \(c > 0\)
Both A and B
Neither A nor B
Products
Pf: