GATE never asks how many milliseconds a program takes. It asks how the running time or memory grows as the input size n 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,g be non-negative functions of n.
Notation
Meaning
Formal condition
f=O(g)
f grows no faster than g
∃c>0,n0: f(n)≤cg(n) for all n≥n0
f=Ω(g)
f grows at least as fast as g
∃c>0,n0: f(n)≥cg(n) for all n≥n0
f=Θ(g)
same growth
f=O(g) and f=Ω(g)
f=o(g)
strictly slower
for every c>0, f(n)<cg(n) eventually
f=ω(g)
strictly faster
for every c>0, f(n)>cg(n) eventually
A useful test: if L=limn→∞f(n)/g(n) exists, then L=0 means f=o(g), 0<L<∞ means f=Θ(g), and L=∞ means f=ω(g). The limit may fail to exist (for example f(n)=n1+sinn), in which case use the definitions directly.
Properties worth remembering
Transitivity holds for all five notations.
Reflexivity holds for O, Ω, Θ but not for o, ω.
Symmetry: f=Θ(g)⟺g=Θ(f).
Transpose symmetry: f=O(g)⟺g=Ω(f), and f=o(g)⟺g=ω(f).
O(f)+O(g)=O(max(f,g)) and O(f)⋅O(g)=O(fg).
Not every pair is comparable: n and n1+sinn are neither O nor Ω of each other.
Logs of any base differ by a constant factor, so log2n=Θ(log10n). Bases inside exponents do matter: 2n=o(3n).
alogbn=nlogba. So 4log2n=n2 and 2log2n=n.
Stirling: log(n!)=Θ(nlogn) and n!=o(nn), n!=ω(2n).
To compare two fast-growing functions, compare their logarithms. If logf=o(logg) then f=o(g). The converse fails: logn2=Θ(logn) yet n2=Θ(n).
Counting loop iterations
Most "find the complexity of this code" questions reduce to a sum.
Nested loops both running to n: Θ(n2).
Loop variable multiplied or divided by a constant: Θ(logn) iterations.
Inner loop bound depends on the outer variable: write the sum explicitly. ∑i=1ni=Θ(n2), ∑i=1nlogi=Θ(nlogn), ∑i=1nn/i=Θ(nlogn) (harmonic series).
Geometric sums are dominated by their largest term: 1+2+4+⋯+n=2n−1=Θ(n).
Loop with i=i2 or i=2i style growth: Θ(loglogn) 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(⌊log2i⌋+1)=Θ(nlogn).
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) auxiliary space for merging; recursive binary search needs Θ(logn) stack but iterative binary search needs Θ(1); quicksort needs Θ(logn) stack on average and Θ(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)+n⇒Θ(n2)
T(n)=T(n/2)+c⇒Θ(logn)
T(n)=T(n/2)+n⇒Θ(n)
T(n)=2T(n−1)+c⇒Θ(2n)
T(n)=T(n−1)+T(n−2)+c⇒Θ(ϕn) with ϕ≈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)+n, every full level costs n and the deepest path has log3/2n levels, giving Θ(nlogn).
Master theorem
For T(n)=aT(n/b)+f(n) with a≥1, b>1, compare f(n) with nlogba:
If f(n)=O(nlogba−ϵ) for some ϵ>0: T(n)=Θ(nlogba).
If f(n)=Θ(nlogbalogkn) with k≥0: T(n)=Θ(nlogbalogk+1n).
If f(n)=Ω(nlogba+ϵ) and af(n/b)≤cf(n) for some c<1: T(n)=Θ(f(n)).
The extended case 2 covers k≥0. For k=−1 the answer is Θ(nlogbaloglogn), and for k<−1 it is Θ(nlogba). The theorem does not apply to T(n−1) style recurrences, to non-constant a (such as T(n)=nT(n/2)), or to a<1.
Change of variables
For recurrences with n, substitute n=2m. Then T(n) becomes S(m/2) and logn becomes m. For example T(n)=T(n)+1 becomes S(m)=S(m/2)+1, so S(m)=Θ(logm) and T(n)=Θ(loglogn).
Worked examples
Worked example 1: Ordering four functions
Arrange f1=n!, f2=2n, f3=nlog2n, f4=4log2n in increasing order of growth.
First simplify: f4=nlog24=n2. Take log2 of the rest: logf3=(logn)2, logf2=n, logf1=Θ(nlogn). Since 2logn<(logn)2<n<nlogn, the order is f4<f3<f2<f1. 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)+n. Here nlog39=n2 and f(n)=n=O(n2−1). Case 1: Θ(n2).
(b) T(n)=T(2n/3)+1. a=1, b=3/2, nlogb1=n0=1, and f(n)=1. Case 2 with k=0: Θ(logn).
(c) T(n)=2T(n/2)+n/logn. nlog22=n and f(n)=nlog−1n. Basic case 2 needs k≥0 and case 1 needs a polynomial gap, so the basic theorem fails. A recursion tree gives level i cost n/(logn−i), and summing over logn levels gives n⋅Hlogn=Θ(nloglogn).
Worked example 3: Exact loop count
How many times does the inner body execute for n=8 in the fragment from the loop section above?
For each i the inner loop runs ⌊log2i⌋+1 times: i=1 gives 1, i=2,3 give 2 each, i=4..7 give 3 each, i=8 gives 4. Total 1+4+12+4=21. Asymptotically this is Θ(nlogn).
Worked example 4: Uneven split
Solve T(n)=T(n/2)+T(n/4)+n.
Level 0 costs n. Level 1 costs n/2+n/4=3n/4. Level 2 costs (3/4)2n. The level costs form a decreasing geometric series with ratio 3/4, so the total is at most n⋅1−3/41=4n. Since the root alone costs n, T(n)=Θ(n). The rule: when the subproblem fractions sum to less than 1 and f(n)=n, the answer is linear.
Common traps
O is an upper bound only. "n=O(n2)" is true; saying an algorithm "is O(n2)" does not mean it takes quadratic time.
22n=O(2n) and 3n=O(2n). Constant factors in exponents matter.
log(nk)=klogn=Θ(logn), but (logn)k is not Θ(logn) for k>1.
Master theorem case 3 needs the regularity condition. It almost always holds for polynomial f(n), but check it.
nlogn vs n1.01: the polynomial wins for large n even though it looks close.
A loop that doubles j 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) stack.
Quick revision
Limit test: ratio →0, constant, or ∞ gives o, Θ, ω.
logn!=Θ(nlogn); alogbn=nlogba.
Harmonic sum ∑n/i=Θ(nlogn); geometric sums take the largest term.
Master theorem: compare f(n) with nlogba; equal (times logk) adds one log factor.
n recurrences: substitute n=2m.
T(n)=T(αn)+T(βn)+n: Θ(n) if α+β<1, Θ(nlogn) if α+β=1.
Stack space equals maximum recursion depth times frame size.