Section 5 · 8 min read

Asymptotic complexity

Asymptotic notations, growth-rate ordering, loop counting and the main methods for solving recurrences, including the Master theorem.

On this page
  1. Why asymptotics
  2. The five notations
  3. Counting loop iterations
  4. Space complexity
  5. Solving recurrences
  6. Worked examples
  7. Common traps
  8. Quick revision

Why asymptotics

GATE never asks how many milliseconds a program takes. It asks how the running time or memory grows as the input size nn grows. Asymptotic analysis throws away constant factors and lower-order terms so that two algorithms can be compared independently of machine and compiler. The worst case is the default unless a question says "average" or "expected".

The five notations

Let f,gf, g be non-negative functions of nn.

Notation Meaning Formal condition
f=O(g)f = O(g) ff grows no faster than gg ∃c>0,n0\exists c > 0, n_0: f(n)≤c g(n)f(n) \le c\,g(n) for all n≥n0n \ge n_0
f=Ω(g)f = \Omega(g) ff grows at least as fast as gg ∃c>0,n0\exists c > 0, n_0: f(n)≥c g(n)f(n) \ge c\,g(n) for all n≥n0n \ge n_0
f=Θ(g)f = \Theta(g) same growth f=O(g)f = O(g) and f=Ω(g)f = \Omega(g)
f=o(g)f = o(g) strictly slower for every c>0c > 0, f(n)<c g(n)f(n) < c\,g(n) eventually
f=ω(g)f = \omega(g) strictly faster for every c>0c > 0, f(n)>c g(n)f(n) > c\,g(n) eventually

A useful test: if L=lim⁡n→∞f(n)/g(n)L = \lim_{n\to\infty} f(n)/g(n) exists, then L=0L = 0 means f=o(g)f = o(g), 0<L<∞0 < L < \infty means f=Θ(g)f = \Theta(g), and L=∞L = \infty means f=ω(g)f = \omega(g). The limit may fail to exist (for example f(n)=n1+sin⁡nf(n) = n^{1 + \sin n}), in which case use the definitions directly.

Properties worth remembering

  • Transitivity holds for all five notations.
  • Reflexivity holds for OO, Ω\Omega, Θ\Theta but not for oo, ω\omega.
  • Symmetry: f=Θ(g)  ⟺  g=Θ(f)f = \Theta(g) \iff g = \Theta(f).
  • Transpose symmetry: f=O(g)  ⟺  g=Ω(f)f = O(g) \iff g = \Omega(f), and f=o(g)  ⟺  g=ω(f)f = o(g) \iff g = \omega(f).
  • O(f)+O(g)=O(max⁡(f,g))O(f) + O(g) = O(\max(f, g)) and O(f)⋅O(g)=O(fg)O(f)\cdot O(g) = O(fg).
  • Not every pair is comparable: nn and n1+sin⁡nn^{1+\sin n} are neither OO nor Ω\Omega of each other.

Standard growth order

For constants 0<ϵ<1<c0 < \epsilon < 1 < c and k≥1k \ge 1:

1<log⁡log⁡n<log⁡n<(log⁡n)k<nϵ<n<nlog⁡n<nc<nlog⁡n<cn<n!<nn1 < \log\log n < \log n < (\log n)^k < n^{\epsilon} < n < n\log n < n^c < n^{\log n} < c^n < n! < n^n

Key facts used to place unusual functions:

  • Logs of any base differ by a constant factor, so log⁡2n=Θ(log⁡10n)\log_2 n = \Theta(\log_{10} n). Bases inside exponents do matter: 2n=o(3n)2^n = o(3^n).
  • alog⁡bn=nlog⁡baa^{\log_b n} = n^{\log_b a}. So 4log⁡2n=n24^{\log_2 n} = n^2 and 2log⁡2n=n2^{\log_2 n} = n.
  • Stirling: log⁡(n!)=Θ(nlog⁡n)\log(n!) = \Theta(n\log n) and n!=o(nn)n! = o(n^n), n!=ω(2n)n! = \omega(2^n).
  • To compare two fast-growing functions, compare their logarithms. If log⁡f=o(log⁡g)\log f = o(\log g) then f=o(g)f = o(g). The converse fails: log⁡n2=Θ(log⁡n)\log n^2 = \Theta(\log n) yet n2≠Θ(n)n^2 \neq \Theta(n).

Counting loop iterations

Most "find the complexity of this code" questions reduce to a sum.

  • Nested loops both running to nn: Θ(n2)\Theta(n^2).
  • Loop variable multiplied or divided by a constant: Θ(log⁡n)\Theta(\log n) iterations.
  • Inner loop bound depends on the outer variable: write the sum explicitly. ∑i=1ni=Θ(n2)\sum_{i=1}^{n} i = \Theta(n^2), ∑i=1nlog⁡i=Θ(nlog⁡n)\sum_{i=1}^{n} \log i = \Theta(n\log n), ∑i=1nn/i=Θ(nlog⁡n)\sum_{i=1}^{n} n/i = \Theta(n\log n) (harmonic series).
  • Geometric sums are dominated by their largest term: 1+2+4+⋯+n=2n−1=Θ(n)1 + 2 + 4 + \dots + n = 2n - 1 = \Theta(n).
  • Loop with i=i2i = i^2 or i=2ii = 2^i style growth: Θ(log⁡log⁡n)\Theta(\log\log n) iterations.
for i = 1 to n             // n iterations
    j = 1
    while j <= i           // runs floor(log2 i) + 1 times
        j = 2 * j

The total here is ∑i=1n(⌊log⁡2i⌋+1)=Θ(nlog⁡n)\sum_{i=1}^{n} (\lfloor\log_2 i\rfloor + 1) = \Theta(n\log n).

Space complexity

Count the extra memory beyond the input. Recursion uses stack space proportional to the maximum depth, not to the total number of calls. Merge sort needs Θ(n)\Theta(n) auxiliary space for merging; recursive binary search needs Θ(log⁡n)\Theta(\log n) stack but iterative binary search needs Θ(1)\Theta(1); quicksort needs Θ(log⁡n)\Theta(\log n) stack on average and Θ(n)\Theta(n) in the worst case unless it always recurses on the smaller part first.

Solving recurrences

Substitution and unrolling

Guess a form and prove it by induction, or expand the recurrence until a pattern appears.

  • T(n)=T(n−1)+c⇒Θ(n)T(n) = T(n-1) + c \Rightarrow \Theta(n)
  • T(n)=T(n−1)+n⇒Θ(n2)T(n) = T(n-1) + n \Rightarrow \Theta(n^2)
  • T(n)=T(n/2)+c⇒Θ(log⁡n)T(n) = T(n/2) + c \Rightarrow \Theta(\log n)
  • T(n)=T(n/2)+n⇒Θ(n)T(n) = T(n/2) + n \Rightarrow \Theta(n)
  • T(n)=2T(n−1)+c⇒Θ(2n)T(n) = 2T(n-1) + c \Rightarrow \Theta(2^n)
  • T(n)=T(n−1)+T(n−2)+c⇒Θ(ϕn)T(n) = T(n-1) + T(n-2) + c \Rightarrow \Theta(\phi^n) with ϕ≈1.618\phi \approx 1.618

Recursion tree

Draw the cost at each level and sum. If level costs shrink geometrically, the root dominates. If they grow geometrically, the leaves dominate. If they are equal, multiply one level's cost by the number of levels. For uneven splits such as T(n)=T(n/3)+T(2n/3)+nT(n) = T(n/3) + T(2n/3) + n, every full level costs nn and the deepest path has log⁡3/2n\log_{3/2} n levels, giving Θ(nlog⁡n)\Theta(n\log n).

Master theorem

For T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n) with a≥1a \ge 1, b>1b > 1, compare f(n)f(n) with nlog⁡ban^{\log_b a}:

  1. If f(n)=O(nlog⁡ba−ϵ)f(n) = O(n^{\log_b a - \epsilon}) for some ϵ>0\epsilon > 0: T(n)=Θ(nlog⁡ba)T(n) = \Theta(n^{\log_b a}).
  2. If f(n)=Θ(nlog⁡balog⁡kn)f(n) = \Theta(n^{\log_b a}\log^k n) with k≥0k \ge 0: T(n)=Θ(nlog⁡balog⁡k+1n)T(n) = \Theta(n^{\log_b a}\log^{k+1} n).
  3. If f(n)=Ω(nlog⁡ba+ϵ)f(n) = \Omega(n^{\log_b a + \epsilon}) and af(n/b)≤cf(n)a f(n/b) \le c f(n) for some c<1c < 1: T(n)=Θ(f(n))T(n) = \Theta(f(n)).

The extended case 2 covers k≥0k \ge 0. For k=−1k = -1 the answer is Θ(nlog⁡balog⁡log⁡n)\Theta(n^{\log_b a}\log\log n), and for k<−1k < -1 it is Θ(nlog⁡ba)\Theta(n^{\log_b a}). The theorem does not apply to T(n−1)T(n-1) style recurrences, to non-constant aa (such as T(n)=nT(n/2)T(n) = nT(n/2)), or to a<1a < 1.

Change of variables

For recurrences with n\sqrt{n}, substitute n=2mn = 2^m. Then T(n)T(\sqrt n) becomes S(m/2)S(m/2) and log⁡n\log n becomes mm. For example T(n)=T(n)+1T(n) = T(\sqrt n) + 1 becomes S(m)=S(m/2)+1S(m) = S(m/2) + 1, so S(m)=Θ(log⁡m)S(m) = \Theta(\log m) and T(n)=Θ(log⁡log⁡n)T(n) = \Theta(\log\log n).

Worked examples

Worked example 1: Ordering four functions

Arrange f1=n!f_1 = n!, f2=2nf_2 = 2^n, f3=nlog⁡2nf_3 = n^{\log_2 n}, f4=4log⁡2nf_4 = 4^{\log_2 n} in increasing order of growth.

First simplify: f4=nlog⁡24=n2f_4 = n^{\log_2 4} = n^2. Take log⁡2\log_2 of the rest: log⁡f3=(log⁡n)2\log f_3 = (\log n)^2, log⁡f2=n\log f_2 = n, log⁡f1=Θ(nlog⁡n)\log f_1 = \Theta(n\log n). Since 2log⁡n<(log⁡n)2<n<nlog⁡n2\log n < (\log n)^2 < n < n\log n, the order is f4<f3<f2<f1f_4 < f_3 < f_2 < f_1. Comparing logs is safe here because each gap in the logs is unbounded, not a constant.

Worked example 2: Three recurrences

(a) T(n)=9T(n/3)+nT(n) = 9T(n/3) + n. Here nlog⁡39=n2n^{\log_3 9} = n^2 and f(n)=n=O(n2−1)f(n) = n = O(n^{2-1}). Case 1: Θ(n2)\Theta(n^2).

(b) T(n)=T(2n/3)+1T(n) = T(2n/3) + 1. a=1a = 1, b=3/2b = 3/2, nlog⁡b1=n0=1n^{\log_b 1} = n^0 = 1, and f(n)=1f(n) = 1. Case 2 with k=0k = 0: Θ(log⁡n)\Theta(\log n).

(c) T(n)=2T(n/2)+n/log⁡nT(n) = 2T(n/2) + n/\log n. nlog⁡22=nn^{\log_2 2} = n and f(n)=nlog⁡−1nf(n) = n\log^{-1} n. Basic case 2 needs k≥0k \ge 0 and case 1 needs a polynomial gap, so the basic theorem fails. A recursion tree gives level ii cost n/(log⁡n−i)n/(\log n - i), and summing over log⁡n\log n levels gives n⋅Hlog⁡n=Θ(nlog⁡log⁡n)n \cdot H_{\log n} = \Theta(n\log\log n).

Worked example 3: Exact loop count

How many times does the inner body execute for n=8n = 8 in the fragment from the loop section above?

For each ii the inner loop runs ⌊log⁡2i⌋+1\lfloor\log_2 i\rfloor + 1 times: i=1i = 1 gives 1, i=2,3i = 2, 3 give 2 each, i=4..7i = 4..7 give 3 each, i=8i = 8 gives 4. Total 1+4+12+4=211 + 4 + 12 + 4 = 21. Asymptotically this is Θ(nlog⁡n)\Theta(n\log n).

Worked example 4: Uneven split

Solve T(n)=T(n/2)+T(n/4)+nT(n) = T(n/2) + T(n/4) + n.

Level 0 costs nn. Level 1 costs n/2+n/4=3n/4n/2 + n/4 = 3n/4. Level 2 costs (3/4)2n(3/4)^2 n. The level costs form a decreasing geometric series with ratio 3/43/4, so the total is at most n⋅11−3/4=4nn \cdot \frac{1}{1 - 3/4} = 4n. Since the root alone costs nn, T(n)=Θ(n)T(n) = \Theta(n). The rule: when the subproblem fractions sum to less than 1 and f(n)=nf(n) = n, the answer is linear.

Common traps

  • OO is an upper bound only. "n=O(n2)n = O(n^2)" is true; saying an algorithm "is O(n2)O(n^2)" does not mean it takes quadratic time.
  • 22n≠O(2n)2^{2n} \ne O(2^n) and 3n≠O(2n)3^n \ne O(2^n). Constant factors in exponents matter.
  • log⁡(nk)=klog⁡n=Θ(log⁡n)\log(n^k) = k\log n = \Theta(\log n), but (log⁡n)k(\log n)^k is not Θ(log⁡n)\Theta(\log n) for k>1k > 1.
  • Master theorem case 3 needs the regularity condition. It almost always holds for polynomial f(n)f(n), but check it.
  • nlog⁡nn\log n vs n1.01n^{1.01}: the polynomial wins for large nn even though it looks close.
  • A loop that doubles jj starting from 0 never terminates. Read the initialisation.
  • Counting recursion depth for space, not total calls. Naive Fibonacci makes exponentially many calls but uses only Θ(n)\Theta(n) stack.

Quick revision

  • Limit test: ratio →0\to 0, constant, or ∞\infty gives oo, Θ\Theta, ω\omega.
  • log⁡n!=Θ(nlog⁡n)\log n! = \Theta(n\log n); alog⁡bn=nlog⁡baa^{\log_b n} = n^{\log_b a}.
  • Harmonic sum ∑n/i=Θ(nlog⁡n)\sum n/i = \Theta(n\log n); geometric sums take the largest term.
  • Master theorem: compare f(n)f(n) with nlog⁡ban^{\log_b a}; equal (times log⁡k\log^k) adds one log factor.
  • n\sqrt n recurrences: substitute n=2mn = 2^m.
  • T(n)=T(αn)+T(βn)+nT(n) = T(\alpha n) + T(\beta n) + n: Θ(n)\Theta(n) if α+β<1\alpha + \beta < 1, Θ(nlog⁡n)\Theta(n\log n) if α+β=1\alpha + \beta = 1.
  • Stack space equals maximum recursion depth times frame size.

Further reading

Test this section