Complexity Analysis
Level 5 — Mastery (cross-domain: mathematics + algorithm theory) Time limit: 75 minutes Total marks: 50
Answer all questions. Justify every claim; unproven assertions earn no marks. You may use standard results (Master Theorem, asymptotic identities) but must state them when invoked.
Question 1 — Formal proof & bounds (18 marks)
Let and .
(a) Using the formal definition of Big-O, prove that by exhibiting explicit constants and and verifying the inequality for all . (6)
(b) Prove that by additionally establishing the lower bound . (4)
(c) A colleague claims . Decide whether this is true or false and prove your answer rigorously (i.e. from the definition, using a limit argument). (4)
(d) State and prove that the relation "" is an equivalence relation on the set of eventually-positive functions (reflexivity, symmetry, transitivity). (4)
Question 2 — Recurrences via three methods (18 marks)
Consider the recurrence describing a divide-and-conquer routine:
(a) Explain why the standard Master Theorem (the three-case version for ) does not directly apply, and state which extended case (Case 2 with a log factor) is relevant. (3)
(b) Solve the recurrence exactly by the recursion-tree method: draw/describe the levels, give the work per level, count the levels, sum them, and conclude the asymptotic order of . (7)
(c) Confirm your answer using the substitution method: guess and prove the upper bound for a suitable constant and all by induction. (6)
(d) For the decrease-by-a-constant recurrence , with , give the closed form and its class. (2)
Question 3 — Amortized analysis, cross-domain modelling (14 marks)
A dynamic array (vector) starts empty with capacity 1. On a push operation: if the array is full, its capacity doubles (copying all existing elements to new storage, costing 1 unit per element copied), then the new element is inserted (cost 1). If not full, insertion costs 1.
(a) Using the aggregate method, compute the total cost of consecutive push operations and hence the amortized cost per operation. Show the geometric-series step explicitly. (5)
(b) Re-derive the amortized cost using the accounting method: assign a charge to each push, prove the bank balance never goes negative, and state the amortized cost. (4)
(c) Using the potential method, define a potential function and show it yields the same amortized cost. Verify and . (3)
(d) Physics analogy. A capacitor stores energy ; charging it draws current in bursts. Briefly explain (2–3 sentences) how the potential function plays the role of "stored energy" in smoothing bursty costs, and why the average (amortized) rate is what matters for long-run performance. (2)
Answer keyMark scheme & solutions
Question 1
(a) (6 marks)
Definition: iff with for all . (1)
For : , so ; also . (2) Hence (2) Take , . The inequality holds for all , proving . (1)
(b) and hence (4 marks)
Since all terms of are positive for , . (2) Thus with , : , giving . (1) and . (1)
(c) Is ? — FALSE (4 marks)
Consider (2) As , grows slower than any positive power, so . (1)
Wait — this limit is , which would make it TRUE. Correct evaluation: , so , hence is TRUE. (1 for correct conclusion)
Correct conclusion: the claim is TRUE. The limit above tends to , so . Full marks require identifying the limit and concluding TRUE.
(d) is an equivalence relation (4 marks)
Write for .
- Reflexive: and , so . (1)
- Symmetric: means eventually. Dividing: , so . (1.5)
- Transitive: if (for ) and (for ), then for : , so . (1.5)
Question 2
(a) Why Master Theorem stalls (3 marks) Here , , so . The driving term is , which is not for any constant : it lies between and . (2) The polynomial three-case version fails; we use the extended Case 2: if then . Here . (1)
(b) Recursion tree (7 marks) Root work: . (1) At depth there are nodes, each of size ; work per node . (2) Total work at level : (2) Number of levels: . Summing to : (2) (The leaf level contributes , dominated.) Conclusion: .
(c) Substitution — upper bound (6 marks) Guess . Inductive step, assuming it for : (2) Expand: (2) This is provided For this holds for all (since and the term dominates). Take , ; base case fails, so pick giving . ✓ (2) Hence , matching the tree bound.
(d) Decrease-by-constant (2 marks) . (2)
Question 3
(a) Aggregate method (5 marks) Insertions cost each: total . (1) Doublings occur when size hits ; copy costs are . (2) Geometric series: . (1) Total cost , so amortized cost . (1)
(b) Accounting method (4 marks) Charge per push. (1) Actual insertion uses 1; store 2 credits on the newly inserted element (and, effectively, the "just-copied" region). (1) When the array of size doubles, the elements copied were each charged 2 extra credits since the previous doubling, which exactly pays the copy operations. (1) Balance never negative amortized cost . (1)
(c) Potential method (3 marks) Define . (1) Then (size 0, cap... take convention initially) and since after any doubling size capacity/2 so . (1) Amortized cost : non-doubling push: , size so , total . Doubling push (size , cap ): , , total . (1) Consistent .
(d) Physics analogy (2 marks) acts like stored potential/elastic energy: cheap operations "charge up" (like charging a capacitor storing ), and the rare expensive resize "discharges" it, so the stored energy pays for the burst. (1) Because the potential's contributions telescope, the long-run amortized (average) rate is — the relevant metric for sustained throughput, just as average power, not instantaneous surge current, governs long-run behaviour. (1)
[
{"claim":"f(n)=3n^2+5n log2 n+7 <= 15 n^2 for n=1..1000","code":"import sympy as sp\nok=all(3*n**2+5*n*sp.log(n,2)+7 <= 15*n**2 for n in range(1,1001))\nresult=bool(ok)"},
{"claim":"limit of 5 log2 n / sqrt(n) is 0 (so 5 n log2 n = O(n^1.5))","code":"n=sp.symbols('n',positive=True)\nL=sp.limit(5*sp.log(n,2)/n**sp.Rational(1,2),n,sp.oo)\nresult=(L==0)"},
{"claim":"recursion tree sum n*sum_{j=1}^{L} j equals n*L*(L+1)/2","code":"n,L=sp.symbols('n L',positive=True)\nj=sp.symbols('j')\nlhs=n*sp.summation(j,(j,1,L))\nresult=bool(sp.simplify(lhs - n*L*(L+1)/2)==0)"},
{"claim":"S(n)=sum k = n(n+1)/2","code":"n=sp.symbols('n',positive=True,integer=True)\nk=sp.symbols('k')\nresult=bool(sp.simplify(sp.summation(k,(k,1,n)) - n*(n+1)/2)==0)"},
{"claim":"aggregate doubling copies: sum_{k=0}^{m} 2^k = 2^(m+1)-1 < 2*2^m","code":"m=sp.symbols('m',nonnegative=True,integer=True)\nk=sp.symbols('k')\ns=sp.summation(2**k,(k,0,m))\nresult=bool(sp.simplify(s-(2**(m+1)-1))==0)"}
]