Skip to main content
Artificial Computational Intelligence

Analyzing Recursive Algorithms

Published: 2026-08-09
Level: postgraduate
Audience: Postgraduate students learning to analyze recursive algorithms

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • The basic operation and the general analysis plan — covered in Lecture 1 (The Basic Operation Method)
  • Primitive operations and the RAM model — covered in Lecture 1 (The RAM Model and Primitive Operations)
  • Running time and time efficiency — covered in Lecture 1 (Efficiency: Space and Time)

The previous session covered the running time of ordinary algorithms with no recursive calls. This session turns to recursive algorithms: what they are, how to write their running time as a recurrence, and how to solve that recurrence with the iterative method, the recursion tree method, and the master method.

The road map for this session: first, what recursion is and why the base case exists (3.1). Then a first worked example — recursive maximum (3.2) — which gives us something concrete to analyze. From that example we extract the idea of a recurrence equation and learn the iterative method for solving it (3.3). A general five-step plan for analyzing any recursive algorithm follows, together with the shift from primitive operations to the single basic operation (3.4). That plan is applied to factorial (3.5), Tower of Hanoi (3.6), and counting binary digits (3.7). Then two faster solution methods: the recursion tree method (3.9) and the master method (3.10), with a note on why the substitution method is deferred (3.8). The session closes with exam guidance and the industry view of what these running times mean in practice.

3.1 Recursion and the Base Case

3.1.1 What Recursion Really Means

Hook: How can a procedure that calls itself ever finish? It cannot — unless every self-call is aimed at a smaller version of the same task. That shrinking is the whole secret of recursion.

A recursion is a procedure P calling itself. Almost everyone knows that much. The second half is the part almost everyone ignores: every call to P exists to solve a sub-problem of smaller size. When we call the same procedure P again, we are not solving the same problem again — the input size has shrunk. That shrinking is the catch, and it is also the property we exploit when we analyze the algorithm.

Intuition + analogy: Think of Russian nesting dolls. Every doll contains a smaller copy of itself; the chain of smaller copies cannot go on forever — it bottoms out at the tiniest solid doll, which contains nothing. A recursive call is the same: each call opens a smaller copy of the problem, and the copies keep shrinking until one of them is small enough to answer directly without any further copies. The analogy breaks in one place: a nesting doll only contains smaller dolls, while a recursive call returns an answer back up the chain — the inner calls hand their results to the calls that opened them.

Why does the size need to shrink? If every call solved a problem of the same size, the calls would never make progress toward an answer. The shrinking is what eventually lets the chain of calls reach a stopping point. Keep this in mind for every recursive algorithm: the calls form a chain of smaller and smaller versions of the original problem, and each version feeds the next.

Formalize — the two-part structure of every recursive procedure: A recursive procedure P is defined by exactly two kinds of rules:

  • The recursive rule (otherwise case): for inputs above some threshold, P's definition contains a call to P itself on a strictly smaller input. The smaller size is what guarantees progress: after enough applications of the rule, the input must fall below the threshold.
  • The direct rule (base case): for inputs at or below the threshold, P is answered directly — no call to itself appears anywhere in that branch.

The textbook treatment of divide-and-conquer states the same structure in three steps applied at every level of recursion: divide the problem into smaller instances of itself, conquer by solving them recursively (and solve directly once they are small enough), and combine the sub-solutions into the full answer. Recursive maximum, factorial, Tower of Hanoi, and binary-digit counting in this session are all instances of this pattern: one rule that recurses on a smaller size, and one rule that answers the smallest case outright.

3.1.2 The Base Case

A base case is the smallest unit of a recursive algorithm that can be solved directly, without using recursion. If every call needed another recursive call, the procedure would keep running forever. The base case is what stops it.

So a recursive procedure should always define a base case, and that base case must be small enough to be solved directly. Whenever you hear "base case," this is what it means: the smallest instance, answered directly, with no recursion involved. Every recursive algorithm needs two parts — the base case and the otherwise case — and a correct recurrence for it will have both as well.

Assumptions & scope: The base case must be reachable. That means two things must both hold: (1) the recursive rule must reduce the size by a strictly positive amount on every application, and (2) the base case must sit at the bottom of that chain of sizes. If the recursive rule halves the input, then the input sizes are — the base case must live at some size in that chain (typically 1), or the recursion will skip past it. If a rule reduces to but the base case tests , the chain still reaches it, so that is fine. What fails is a base case sitting above the shrinkage pattern — e.g., a rule that reduces to paired with a base case at would miss 3 forever and never stop. Also note: the exact number at which the base case triggers (1, 2, or 100) does not matter for the asymptotic running time, only that it is a constant size solved directly — a point the professor returns to with in the recursion-tree discussion.

Visual intuition: Picture a chain of boxes labeled with decreasing sizes — . Each box points to the next smaller box (that is the recursive call), and the box labeled 1 is drawn solid: it points to nothing, because it holds the direct answer. The chain is the recursion; the solid box is the base case. The takeaway: a correct recursion is a chain that always ends in a solid box.

Pitfalls:

  1. Forgetting the base case entirely — the classic infinite recursion. Every call creates a new call of the same size, so the chain never ends; in a real program the machine eventually runs out of memory on the call stack, but conceptually it "keeps running forever."
  2. Calling the same size instead of a smaller size — e.g., a procedure that calls itself with instead of . Even with a base case in the code, this branch never reaches it.
  3. Confusing "base case" with "basic operation." These are different ideas: the base case is the smallest instance answered directly; the basic operation is the statement that executes the most times inside the recursion. The professor will later warn that writing "base operation" (mixing the two) is cut to zero on the exam.
  4. Treating the base case's cost as the whole story — the base case is also a term in the recurrence equation (its constant time), so a correct recurrence has a base-case line and an otherwise line.

Recap + bridge: Recursion is a procedure calling itself on strictly smaller sub-problems, and the base case is the smallest instance that is answered directly — together they guarantee the call chain eventually stops. The next section makes this concrete: a recursive maximum-finding procedure is traced by hand, so you can watch the chain expand down to the base case and then unwind back up with answers.

Real-world connection: recursion is the mechanism behind the divide-and-conquer algorithms that run much of modern computing — merge sort (which sorts the arrays in a database engine), binary search (which finds a record in a sorted index in time), and recursive tree traversals (which walk file systems and parse expressions in compilers). In every one of them the same two-part contract appears: shrink the input, and answer the smallest case directly. Recursion is also how self-similar data is handled naturally — think of a folder tree inside a filesystem, where every folder is a smaller version of the whole tree: an engineer analyzing the time a filesystem crawler takes writes a recurrence, exactly as this session will now do.

3.2 Recursive Maximum: The First Worked Example

3.2.1 The Algorithm

Hook: You already know how to find the maximum of an array with a loop — so why study a recursive version that does the same job? Because it is the simplest possible case where a procedure calls itself, and the way its calls shrink lets us see — in full, on paper — everything that goes on inside a recursive algorithm. Every recursive running-time analysis in this session builds on this picture.

The recursive algorithm for finding the maximum element is introduced as a contrast to the ordinary version seen in earlier sessions. Input: an array a storing integers. Output: the maximum element in a.

recursiveMax(a, n):
    if n = 1:
        return a[0]
    else:
        return max( recursiveMax(a, n - 1), a[n - 1] )

Formalize — reading the procedure line by line:

  • Parameters: the call comes with two arguments — the array a and the size n. The size is the parameter that shrinks; the array is passed along unchanged so every call works on the same data.
  • Base case (line 2–3): if only one element remains (), that element is , and it is by definition the maximum of a one-element array. Answer directly; no recursion.
  • Recursive case (line 5): the maximum of the first elements is computed as

The reasoning: the maximum of the whole array is the maximum of "the maximum of the first elements" and "the last element." Whatever the biggest element of the first is, comparing it against the final element either keeps it or replaces it — in both cases we get the true maximum of all elements.

  • Shrinking check (the recursion contract from 3.1): the recursive call uses size , and the base case sits exactly at the bottom of the chain . So the calls must eventually stop.

3.2.2 The Trace, Step by Step

Worked example — trace on a real array. Work it with a concrete array: and , so .

Phase 1 — expand the calls downward (toward the base case):

  1. Call recursiveMax(a, 5). Is ? No. Return , and . The call recursiveMax(a, 4) is not yet evaluated — it will be computed first.
  2. That call expands: recursiveMax(a, 4) also has , so it returns , and .
  3. recursiveMax(a, 3) returns , and .
  4. recursiveMax(a, 2) returns , and .
  5. recursiveMax(a, 1): now , so it returns . This is the base case; no further recursion.

The chain has reached the bottom. Note what has accumulated: a stack of pending max comparisons, each waiting for the value of the call below it.

Phase 2 — unwind the chain upward (with concrete values):

  • The deepest call returned 4 (recursiveMax(a, 1) = a[0] = 4). Plug it into the call from step 4: , returned to the previous call;
  • , returned up again;
  • , returned up again;
  • the final answer.

Answer: the maximum of is 5.

Sense-check: 5 really is the largest entry of the array (the other entries are 4, 3, 2, and 1), and the recursion reported exactly 5 — the mechanics, not the numbers, did the work. Also note the honest price of the recursion: the answer 5 is reached only after the base-case value 4 travels back up through four comparisons. That chain of work is exactly what the recurrence equation of the next section will count.

The pattern holds for any recursive trace: expand the calls one by one until the base case is reached, then solve back, substituting values. Even if the idea does not click on first reading, run it yourself once with a small array — the mechanics are simple.

Visual intuition: Draw the five calls as a vertical stack of boxes — recursiveMax(a,5) on top, then (a,4), (a,3), (a,2), and the solid-boxed recursiveMax(a,1) at the bottom (the base case). Each box carries the one extra element it will compare against the answer coming up from below: 1, 5, 2, 3, and 4 at the base. The arrows point down while expanding, then flip upward while returning values. The takeaway: recursion builds a stack, and the base case supplies the first value that stack processes.

Pitfalls:

  1. Thinking each call "recomputes the whole problem." recursiveMax(a, n-1) does not re-scan the array from scratch — it solves the smaller problem "max of the first elements," and each level adds exactly one new comparison. The total work is a chain of comparisons, not of them.
  2. Evaluating the max too early. When step 1 writes "return max(recursiveMax(a,4), a[4])", the value of recursiveMax(a,4) is unknown — you must descend first, then come back. Beginners who "substitute 4 and 1" immediately mis-trace.
  3. Missing the base case's role in the value flow. The number 4 that starts the unwinding comes from the base case. If the base case returned something wrong (say instead of ), every answer above it would be wrong too — one bug at the bottom poisons the whole chain.
  4. Ignoring the recursion contract. If someone "optimized" this procedure by calling recursiveMax(a, n) (same size), it would never end. Every recursive call must move toward the base case.

Recap + bridge: The recursive maximum computes the maximum of elements as the maximum of "the maximum of the first elements" and the last element — the calls expand down to the base case , which returns , and the chain unwinds back up with the answer. The next section asks the natural follow-up question: how many primitive operations does this whole chain of calls cost? That question is answered by writing the algorithm's running time as a recurrence equation.

Real-world connection: this exact pattern — "combine the answer for the rest of the data with the current element" — is the shape of recursive reduce operations used in distributed data processing (for example, computing the max, sum, or count over millions of records in a map-reduce-style pipeline). A single machine cannot hold all records, so the problem is cut into smaller parts, each part is reduced to a small answer, and the small answers are combined upward — precisely the expansion-then-unwind flow traced above, scaled to a cluster of machines.

3.3 Recurrence Equations and the Iterative Method

3.3.1 What a Recurrence Is

Hook: For a loop-based algorithm you can count iterations directly. But a recursive algorithm's running time is defined in terms of its own running time on smaller inputs — how do you solve an equation that contains the thing you are solving for? The answer is the subject of this whole section: write the self-referential description, then unwind it until the unknown disappears.

A recurrence is an equation or inequality that describes a function in terms of its values on smaller inputs. That fits recursive calls perfectly: the running time of a recursive algorithm satisfies such statements, and those statements are called a recurrence equation.

Formalize — the notation:

  • is the running time of the algorithm on an input of size — the same notation used in the previous session for ordinary algorithms. The letter is a free choice; any letter works (this session later uses and for different algorithms). is used because time starts with T.
  • A recurrence equation is a two-line description: one line for the base case (small , solved directly, costing a constant) and one line for the recursive case (larger , expressed through of smaller sizes plus the extra work done at this level).
  • The phrase "in terms of its values on smaller inputs" is what makes a recurrence different from an ordinary equation: the unknown function appears on the right-hand side, evaluated at smaller arguments. That self-referential form is exactly the shape of the recursive call itself — a recurrence is the running-time mirror of the algorithm that produces it.

Recurrence definition (standard form): reference treatments state the same idea verbatim: a recurrence is an equation or inequality that describes a function in terms of its value on smaller inputs. The merge-sort recurrence with base case is the canonical textbook example of the form — two cases, recursive term first, extra work added at each level.

3.3.2 Writing the Recurrence for Recursive Maximum

A recursive algorithm must have two cases, and so must its recurrence: the base case and the otherwise case.

Base case, : . Where does the 3 come from? Count the primitive operations performed when : the comparison (one operation), the return statement (one operation), and the array indexing (one operation). That makes 3. The exact value is not important — the point is that the base case takes constant time.

Otherwise: . The is the time spent inside the recursive call on an input of size . The stands for everything else in the recursive part: one return statement, one max calculation, one recursive call, and the array indexing — four primitive operations — plus the three operations of the base case, because the recursive call eventually ends in the base case: .

Put together, the recurrence for recursive maximum is:

For this first algorithm the primitive counting is done in full to show the minute details. From the next algorithm onward, primitive counting is abandoned.

Q: How does that 7 come about? Counting primitive operations in the recursive part gives only 4: one return, one max calculation, one recursive call, and one array indexing.

A: The recursive call also ends in the base case, so the 3 operations of the base case are added on top: . Whenever the recursion runs, the base condition still executes at the end of the chain, so its cost is included in the recursive call rather than counted separately. But there is no need for this micro detail going forward — only the fact that it is a constant matters.

3.3.3 Solving the Recurrence with the Iterative Method

The goal is a closed form: a version of the equation with no reference to the function on the right-hand side. With on both sides, we cannot solve for yet.

Intuition + analogy: Think of a maintenance budget for a chain of workstations. Every workstation costs 7 rupees to service and then passes the job to the next workstation, which is one step closer to the end of the chain; the last workstation is the base case, costing 3. The total bill is "3 for the last one, plus 7 for each of the service stops" — but to prove that, you cannot just assert it: you unwind the chain one station at a time and watch the pattern emerge. That unwinding is the iterative method.

Worked example — the iterative method in full. Start from the recurrence:

Express using the same recurrence with replaced by :

Substitute that back in:

Repeat once more:

These are mere substitutions, nothing more. After substitutions the general form is:

The general form still has on the right, so it is not yet closed. Which value of turns the right-hand side into a case we know? The base case is , so we want , meaning . (If we had set , we would get — and we do not know , so there would be nothing to substitute.) This is the thought process behind choosing : use the information you actually know. Substituting and the known base value:

So .

Numerical sense-check: try . The formula gives . Directly from the recurrence: , then , , , . Both routes agree.

Now express it asymptotically. Since , the value is bounded above by , and constants are dropped:

Q: Why big-O and not big-Omega or big-Theta when the exact value is ?

A: is less than , so is an asymptotic upper bound, and big-O is the upper-bound notation. We are not worried about the constant, so is simply . The negative constant is a hint: the value sits below a clean multiple of , so an upper bound is the natural statement.

Assumptions & scope: The recurrence assumes is a whole number with , and the base case costs a constant (here counted as 3). The exact constants (3 and 7) are an artifact of the primitive-operation bookkeeping convention — another convention might count a comparison as 2 or an assignment as 1 and get different numbers. That is fine and expected: the constants only matter here for pedagogy. What must survive every convention is the structure: a constant base case and a constant add-on per recursive level. Asymptotically, any constant base case and any constant add-on produce — linear growth. Changing from 3 to 100 changes the exact solution but not the order of growth.

Visual intuition: Plot against — horizontal axis: input size (units: elements of the array); vertical axis: (units: primitive operations). The curve is a straight line starting at and rising with slope 7 — each added element adds exactly 7 operations. The landmarks: the y-intercept at (base-case cost 3) and the slope (per-element cost 7). The takeaway: a recurrence of the form always draws a line — one recursive call of size means every input size adds the same constant, so the total is proportional to .

Pitfalls:

  1. Choosing the wrong stopping point. The general form must be closed using the base case you actually know. If you substitute you reach , which the recurrence never defined — the derivation then dead-ends. Always ask: which value of lands on a known base case?
  2. Stopping too early. Reaching is not the answer — it still contains on the right. The closed form is reached only when the right-hand side is fully known.
  3. Confusing the meaning of . is the total running time of the whole smaller call — everything inside it — not "one step." Adding +7 on top of it is correct because the +7 is the work of the current level only.
  4. Dropping the negative constant sloppily. being "less than " is precisely the justification for big-O. Saying "7n − 4, so Theta(n)" would need a matching lower bound (here for would work), but the lecture's choice of the upper-bound statement is the safer, cleaner one.

Exam note: Time calculations of exactly this kind — counting the base case, writing the recurrence, solving it — will be asked in the quiz. The quiz comes after session four; this is the drill the professor stressed more than once.

Recap + bridge: A recurrence describes the running time of a recursive algorithm through its own values on smaller inputs — two lines, a base case and a recursive case; the iterative method unwinds the recursive case by repeated substitution until a pattern appears, then closes the pattern at the known base case, giving . Before the next example, the lecture steps back and lays out the general five-step plan for analyzing any recursive algorithm — and replaces primitive-operation counting with the single basic operation.

Real-world connection: when an engineer profiles a slow program and finds a function that keeps calling itself once per input element, the recurrence is the tool that predicts the problem: double the input, double the time, because the plot is a straight line. The same analysis, with , tells you that a naive recursion that strips one element per call (like this maximum-finder, or a recursive string reversal) scales linearly — fine for a few thousand records, and exactly the reasoning a database or web-service engineer uses before choosing a loop, a recursion, or a divide-and-conquer split.

3.4 The General Plan and the Shift to Basic Operations

3.4.1 The Five-Step Plan

Hook: Every recursive algorithm in this course — and on the quiz — is analyzed by the same five moves. Learn the moves once, and each new algorithm is just a new set of numbers inside the same skeleton.

Before the next example, the general plan for analyzing any recursive algorithm:

The five-step plan (procedure):

  1. Identify the parameter to be considered, based on the size of the input. For us that parameter is . Everything later refers back to this choice: the base case tests it, the recurrence decreases it, and the final answer is a function of it.
  2. Get the number of times a basic operation is executed. The basic operation is the statement that dominates the running time (defined precisely in 3.4.2); we count how many times it runs, not how many times every statement runs.
  3. Get the initial condition — the base case. The smallest instance, where the basic operation count is known directly.
  4. Get a recurrence relation. Assemble the previous two ingredients into the two-line equation: the base case line plus the recursive-case line.
  5. Solve the recurrence relation, get the order of growth, and express it in asymptotic notation. Use the iterative method (3.3), the recursion tree method (3.9), or the master method (3.10) to reach the closed form, then report it in , , or notation.

When this plan works and when it bends: The plan assumes the input is described by one size parameter , which is the standard setting for this course's algorithms. It extends naturally when a problem has two size parameters (e.g., an matrix) — step 1 then picks the parameter that governs the recursion, and the final order of growth may involve both. The plan also assumes the basic operation is identifiable inside the recursion; for algorithms whose cost is dominated by the merge/combine step (like merge sort, where the comparisons are the basic operation), step 2 is still carried out in the recursive part — comparisons happen there — so the plan survives. What the plan does not do is tell you which of the three solving methods to use; steps 1–4 are mechanical, step 5 is where judgment enters.

3.4.2 Primitive Operations Are Out; Basic Operations Are In

The recursive-maximum analysis counted every primitive operation, for the sake of understanding the minute details. That method is now abandoned. From here on only the basic operation matters — the statement that contributes the most to the running time. Primitive operations are forgotten entirely; the basic operation alone decides the order of growth.

What counts, exactly: the basic operation (sometimes called the basic step in reference texts) is the statement that executes the maximum number of times and so dominates the running time. The idea matches the standard textbook practice of isolating one dominant cost — like comparisons in a sorting algorithm or multiplications here — and ignoring the rest. Every other statement's executions are at most a constant factor of the basic operation's count, so they cannot change the order of growth.

How do you find the basic operation in a recursive algorithm? Look in the recursive part, not the base case. In a recursive algorithm, recursion is what matters, so the basic operation is the one executing the maximum number of times inside the recursion. There is no thumb rule to apply blindly: just look at the algorithm, see which operation runs most often, and treat everything else as a constant.

Intuition + analogy: Measuring an algorithm by its basic operation is like estimating a highway trip by the time on the highway stretches and ignoring the few minutes of traffic lights at the ends: the lights are constant regardless of distance, so the trip's growth is decided entirely by the highway. The basic operation is the "highway" statement — it runs once per recursive level (or per iteration), so its count grows with ; the rest are "traffic lights" — a constant number per level, irrelevant at scale.

Visual intuition: Picture a horizontal bar for every statement in the algorithm, drawn to scale with its execution count on the horizontal axis. The bars for the base-case statements are stubby and flat — they do not grow with . The bar for the recursive-part statement is long and keeps growing as grows. The basic operation is the longest bar, and the total height of the stacked picture is dominated by it; the stubby bars are absorbed into the constant. One-sentence takeaway: in a recursive algorithm, the longest bar always lives inside the recursion.

Pitfalls:

  1. Hunting in the base case. The base case runs once, so none of its statements can be the basic operation — it executes a constant number of times. Look inside the recursive part.
  2. Counting everything "just to be safe." That was the primitive-operation approach, explicitly abandoned. Counting extra statements may change the constant but cannot change the order of growth — the point of the shift.
  3. Inventing a thumb rule. There is none. Two recursive algorithms can have different basic operations (factorial's is multiplication; a recursive comparison-based search's is the comparison); the only reliable method is to read the algorithm and see which operation runs the most times.
  4. Forgetting that the base case still exists. Dropping primitive counting does not drop the base-case line of the recurrence — the initial condition (plan step 3) still comes from the base case, but its value is now counted in basic operations only (often 0 or 1), not in every primitive.

Recap + bridge: The general plan is five moves — size parameter, basic-operation count, base case, recurrence, solve and state asymptotics — and the dominant cost to count is the single basic operation inside the recursive part. The next section applies this immediately: factorial's recurrence , whose basic operation is the multiplication.

Real-world connection: this is the same move every performance engineer makes when a profiler flags a function: find the single hottest line (the basic operation) and ignore the rest, because optimizing a line that runs once per call does nothing for the order of growth. When a service is slow, the question is never "how many statements run?" but "which statement runs once per element, and how many elements are there?" — exactly the two questions steps 2 and 1 answer.

3.5 Factorial: Basic Operations in Action

3.5.1 The Algorithm and Its Recurrence

Hook: You have multiplied since school — but how many multiplications does the recursive version actually perform? Counting the answer with the new basic-operation rule is the first real application of the five-step plan.

The factorial function, known since elementary school, written recursively:

factorial(n):
    if n = 0:
        return 1
    else:
        return n * factorial(n - 1)

Step 1 of the plan — the size parameter is . Step 2 — the basic operation is multiplication. The recursive call factorial(n-1) is not an operation to count; the operation that contributes the most running time is the multiplication . It sits in the recursive part (the rule from 3.4.2), and it runs exactly once per recursive call — no other statement in the algorithm is executed more often.

So the recurrence has two cases. Step 3 — the base case, : when , no multiplication happens at all — only a return of 1 — so . Step 4 — the recursive case:

The is the time to compute factorial(n-1), and the is the one multiplication that finishes the job.

Worked example — counting the multiplications directly. Run factorial(4) by hand, marking each multiplication:

  1. factorial(4)4 * factorial(3) — multiplication 1, call on 3.
  2. factorial(3)3 * factorial(2) — multiplication 2, call on 2.
  3. factorial(2)2 * factorial(1) — multiplication 3, call on 1.
  4. factorial(1)1 * factorial(0) — multiplication 4, call on 0.
  5. factorial(0) → returns 1 — no multiplication.

Then the values flow back: factorial(1) = 1·1 = 1, factorial(2) = 2·1 = 2, factorial(3) = 3·2 = 6, factorial(4) = 4·6 = 24.

Answer: multiplications — exactly . The recurrence predicted , and the hand trace confirms: with , four multiplications happened and the base case contributed zero. Sense-check: 24 is the correct value of , and the multiplication count equals the number of recursive levels, so for every .

Q: What is the value of the base case? Some said 2, others said 1.

A: Using the basic-operation method it is 0: when no multiplication is performed, only a return of 1. The wrong guesses drew a playful warning that in a live class the guessers would have had to hold their ears.

Q: Why is the return statement not the operation executing most?

A: Forget primitive operations completely. In recursive algorithms, check the recursive part for the basic operation, because recursion is what matters. The return statement lives in the base case; treat everything outside the recursive part as a constant.

3.5.2 Solving the Recurrence

Worked example — the iterative method. , so express the same way and substitute:

Keep going to the general form:

The known base case is , so choose to bring onto the right-hand side (unlike recursive maximum, whose base case sat at and required , here the base case is at , so the full substitutions are needed):

Answer: is exactly , so:

Sense-check: for the formula gives , matching the hand trace above — the closed form reproduces the direct count.

Q: Shouldn't also be counted along with the multiplication?

A: already stands for the time taken to solve the problem of size — it includes everything that happens inside that call. The +1 is only the last multiplication, the one that combines with the result of the smaller call.

Q: How does the answer come out as theta of N?

A: Because came out exactly . If it had been , we would have written big-O; if the leftover term were asymptotically lower than , big-Omega. The +1 is just a constant — it could even be something like , anything asymptotically lower than .

Assumptions & scope: The count assumes multiplication costs the same regardless of the operands — the standard constant-cost assumption for the basic-operation model, and fine for order-of-growth analysis. If the numbers get huge (say , where has 2568 digits), a real computer pays more for big-number multiplication, but that cost is a property of the arithmetic library, not of the recursion structure; the number of multiplications is still . Also note the base-case position matters for the closed form: factorial's base case at gives exactly ; recursive maximum's base case at gave . Same shape of recurrence, different constants and different base positions — and the same linear order of growth either way.

Visual intuition: Imagine a staircase with steps, one step per recursive level, and each step costing exactly one multiplication; the floor below the first step is the base case, costing 0. The total climbing cost is the number of steps — the staircase's height is . One-sentence takeaway: one recursive call of size plus one unit of work draws a straight staircase, total height exactly , so .

Pitfalls:

  1. Guessing the base case from the return value. The base case returns 1, but its cost is 0 — no multiplication runs there. Cost and returned value are different things; students who answer "1" or "2" are pricing the value instead of the operations.
  2. Counting the recursive call as a primitive operation. factorial(n-1) is not an operation with a cost of its own — its whole cost is by definition. Adding +1 for it would double-count.
  3. Writing when the closed form is only an upper bound. Theta was correct here only because the solution is exactly . For a bound like " or less," big-O would be the honest notation.
  4. Carrying primitive-operation habits into the base case. With the old method, the base case of factorial would have cost something like 1 (the return); with the basic-operation method it costs 0 because no multiplication runs. Both are constants — but the exam-relevant value under the new method is 0.

Recap + bridge: Factorial's basic operation is the multiplication in the recursive part; the recurrence , solves to exactly , so — the first clean application of the five-step plan. The next algorithm is the classic Tower of Hanoi, whose recursion doubles the work at every level — and whose analysis introduces geometric progressions.

Real-world connection: the factorial count multiplications is the running time of a straightforward recursion; this is why real systems compute factorials iteratively, and why the number of combinations — which appears in probability and statistics packages — is evaluated with tables or optimized routines rather than by direct factorial recursion: the recursion itself is linear, but the values explode. Counting the basic operation is how a systems engineer explains why a "trivial" recursion is or is not the bottleneck before writing it into a library.

3.6 Tower of Hanoi

3.6.1 The Problem

Hook: A puzzle with just three pegs and a handful of disks — how many moves does a complete solution need? The answer grows so fast that 64 disks would outlast the universe. Watching the number of moves explode is where this course first meets exponential time.

Tower of Hanoi is one of the classic complex problems. We have disks of different sizes and three pegs. Initially all disks sit on the first peg, stacked in order of size — the largest on the bottom, the smallest on the top. The goal is to move all disks to the third peg, using the second peg as an auxiliary when needed. Two rules govern every move: move only one disk at a time, and never place a larger disk on top of a smaller one — at any time.

3.6.2 The Recursive Algorithm

The recursive algorithm has only three steps:

hanoi(n, source, destination, temp):
    if n = 1:
        move the disk from source to destination
    else:
        hanoi(n - 1, source, temp, destination)   # move n-1 disks off the way
        move the nth disk from source to destination
        hanoi(n - 1, temp, destination, source)   # move n-1 disks onto the target

Reading the three steps:

  • Base case (): a single disk moves straight from source to destination — one move, no recursion.
  • Step 1 — clear the way: move disks from source to temp, using destination as an auxiliary peg — you move one disk at a time, and "somehow" you do it; that "somehow" is the recursive call hanoi(n-1, source, temp, destination). Why is this legal? The destination peg is the spare, so the largest disk can wait untouched on source.
  • Step 2 — the biggest disk: once those disks are gone, the source holds only the nth (largest) disk, so move it straight from source to destination. The destination is empty or holds only bigger disks, so the rule "no larger on smaller" is respected.
  • Step 3 — rebuild the tower: move the disks sitting on temp from temp to destination, using source as an auxiliary — the recursive call hanoi(n-1, temp, destination, source).

The two recursive calls both operate on size , which is smaller than — the recursion contract from 3.1 holds, and the chain bottoms out at . A short YouTube walkthrough (a link was shared) makes the sequence of moves much easier to follow than a written description.

3.6.3 Recurrence and Analysis

The time function here is called instead of — the letter is a free choice, and is the same idea as .

Base case: . With a single disk, one move takes it from source to destination — one basic operation (the basic operation here is a disk move).

Otherwise: the time to solve a problem of size equals the time to move disks from source to temp, plus the time to move the nth disk, plus the time to move disks from temp to destination:

Two sub-problems of size (so the ) and one extra move for the largest disk (the ).

Worked example — the iterative method with the geometric progression. Now solve it by the iterative method. Expand using the same recurrence:

One more step, and the coefficient doubles at every expansion:

The pattern after expansions: the leading coefficient is , and the tail is the geometric progression . The general form:

The tail is a geometric progression with first term 1 and common ratio 2. The sum of a GP with first term , common ratio , and terms is , so the tail sums to . (This is the standard geometric-summation result — in binary arithmetic it is the familiar fact that , the largest integer representable with bits.) This is where geometric progressions enter the analysis — refresh GP formulas along with logarithms and arithmetic progressions.

The known base case is , so choose :

Answer:

Numerical sense-check: for , the formula gives — and the classic puzzle with three disks is indeed solved in exactly 7 moves (small disk to temp, medium to destination, small onto medium, large to destination, small to temp, medium onto large, small onto large). The formula matches the puzzle's known answer.

Asymptotically:

Q: Shouldn't that last 1 be dropped, since it is already in the base case when ?

A: No. That 1 pays for the move of the nth disk from source to destination — the one move of the largest disk. It has nothing to do with the base case.

Q: Could the constant be 2, 3, or 4 instead of 1?

A: It does not matter. As long as the part is correct, the answer stays . Constants do not matter much — you will see this again as you do more exercises.

Assumptions & scope: The recurrence holds for any with a single move of the largest disk per level — the "+1" is structural, not a counting convention: it is one disk move, genuinely performed. Note what the solution does not assume: no powers-of-two assumption, no divisibility — can be any whole number, because the size shrinks by exactly 1 per level. (Contrast this with the halving recurrences of 3.7 and 3.9, which need the power-of-two trick.) Also, is the answer for the number of moves; the space used by the recursion is different — only stack frames, i.e., memory — a fact worth keeping straight in interviews.

Visual intuition: Draw the recursion tree of hanoi(3, ...): the root is the single move of disk 3, its two children are the two recursive towers of size 2, each of those splits into two size-1 leaves — 1 + 2 + 4 = 7 nodes, one per actual disk move. Vertical axis: depth of recursion (levels 0, 1, 2); horizontal axis: the tree's leaves. The tree is perfectly balanced and every node is a real move; the total node count doubles at each level, which is the geometric series in action. One-sentence takeaway: when every problem spawns two sub-problems of size , the tree's node count is a GP summing to .

Pitfalls:

  1. Dropping the "+1" as if it were a counting artifact. It is a real move — the largest disk travels exactly once. The recurrence without it () would solve to , wrong by a factor of 2 and inconsistent with the 7-move solution for .
  2. Forgetting the GP sum formula at the moment of need. The tail must be recognized as a geometric progression; students who try to count it term by term lose the pattern. The GP formula is explicitly refreshable material for this course.
  3. Writing loosely. The professor writes . Since is exact, is also true — but the upper-bound habit (big-O) is the safer default statement, as emphasized repeatedly in this lecture.
  4. Treating exponential time as a code smell by default. The professor's point is the opposite: for problems whose nature is exponential (Hanoi), no faster algorithm exists, and the exponential algorithm is the right one. The error is choosing exponential when a linear algorithm does exist.

Exam note (playful warning from the professor): teachers tend to teach three plus two and then ask square roots and powers. This exercise is deliberately harder than the ones that came before — do it yourself rather than waiting for the worked version.

Recap + bridge: Tower of Hanoi's recurrence , doubles the sub-problems at every level; the iterative method turns the tail into the geometric progression , summing to , so the algorithm is . Exponential time is the problem's own nature — accepted when no better algorithm exists, but a poor excuse when a linear one does. The next algorithm, counting binary digits, changes the recurrence's shape completely: the size halves each level, and solving that recurrence needs the power-of-two assumption and logarithms.

Real-world connection: the number also shows up as the exact cost of a famous real system: the backup-tape or "disk tower" discipline in early mainframe operations (the recursive algorithm for moving the disks was used in practice for tape rotation schedules). More broadly, exponential blow-up is the reason engineers count operations before building: a feature that doubles work per input level cannot run on production data — the same arithmetic that says "64 disks need moves" says "a doubling recursion over a million records is dead on arrival," and the analysis that proves it is exactly the recurrence solved here.

3.7 Counting Binary Digits

3.7.1 The Algorithm and Its Recurrence

Hook: How many bits does the number 1,000,000 need? Guessing is hard; halving is not. The recursion that counts binary digits halves the number at every step — and the number of halvings turns out to be a logarithm. This is the first recurrence where the input size shrinks by division, and it introduces the logarithms that reappear in every divide-and-conquer analysis.

Here is an algorithm to find the number of binary digits in the binary representation of a number . If , it returns 1; otherwise it halves the number and adds one — every halving accounts for one binary digit.

countBinaryDigits(n):
    if n = 1:
        return 1
    else:
        return 1 + countBinaryDigits(n / 2)   # halve the number, add one digit

Formalize — what is being counted. The basic operation here is the halving — the division of the current number by 2 (the operation that executes the maximum number of times, sitting in the recursive part per the rule of 3.4). Let count halvings. The recurrence is easy to write now:

Why is and not something bigger? Because when , no basic operation happens — there is nothing to count. The in the recursive case is the one halving (read differently, the one binary digit added by halving).

Reconciling the algorithm's return value with the recurrence: the procedure returns the digit count — 1 at the base, and one more per halving — so its return value is : the number of halvings plus the final digit that survives at . For example, : halvings are , so , and the algorithm returns — which matches having 4 binary digits. The recurrence with is the standard count of halvings, and it is what the asymptotic analysis is built on.

3.7.2 The Power-of-Two Assumption

The recurrence divides by 2, and division is awkward in a closed form. The trick: assume is a power of two, say , so the divisions disappear. Then:

General form:

Worked example — solving under the assumption. The known base case is , so choose — then — and:

Finally convert back: since , we have , so:

Answer: the number of halvings is exactly when is a power of two, so .

Numerical sense-check: : should be . Directly: — four halvings. The recurrence agrees, and the algorithm returns digits — has 5 bits. Sense-check: the halving chain is exactly as long as the exponent in , because each halving divides the exponent by one: .

Big-O works too; the answer is exactly , so theta is justified. The assumption was only a solving aid — the answer is stated back in terms of . The same trick applies to any recurrence that divides by 2, 4, or any fixed factor: assume the input is a power of the divisor, solve, then substitute of the base.

Assumptions & scope: The clean equality holds exactly for powers of two. For arbitrary , the halving chain ends at 1 after halvings (e.g., is 2 halvings, and ), and the digit count is — the standard formula. The power-of-two assumption is legitimate precisely because it does not change the order of growth: whether is or , the answer is still . This matches the standard textbook practice of analyzing recurrences on exact powers of (here ) and asserting the bound carries over — floors and ceilings do not change the asymptotics. The same caveat applies to any recurrence dividing by a fixed factor : assume , solve, convert with , and the order of growth survives for all .

Visual intuition: Picture the halving chain as a staircase where each step cuts the current number in half. Plot against (horizontal axis: the number ; vertical axis: halvings needed). The curve is a slow, ever-flattening climb — to double the number of halvings you must square . The landmark: every tenfold jump in adds only about 3.32 halvings. One-sentence takeaway: halving-based recursion grows logarithmically — doubling the input adds exactly one more level of work.

Pitfalls:

  1. Counting the base case's return as work. because no halving happens at — the return of 1 is a digit, not a basic operation. Mixing the returned value with the cost is the same confusion the professor flagged in factorial.
  2. Forgetting to convert back from to . The closed form is in terms of the exponent; the final answer must be restated as , i.e., . Leaving the answer as "" fails step 5 of the plan.
  3. Forcing a power-of-two assumption where the recurrence does not halve. The trick works for division by 2, 4, or any fixed factor (assume , substitute ); it is not a generic license for other shapes of recurrence.
  4. Writing "base operation." The correct term is basic operation. The professor's warning is blunt and exam-relevant: "base operation" on the exam is cut and marked zero.

3.7.3 The Right Term: Basic Operation

While the class worked through the exercises, one student wrote "base operation." The correction is sharp, and it is exam-relevant:

Q: Is it "base operation"?

A: It is the basic operation. "Base case" and "basic operation" are different things, and the term matters: if you write "base operation" on the exam, it will be cut and marked zero. And again — there is no thumb rule: look at the algorithm, find the operation that executes the maximum number of times, and in a recursive algorithm check the recursive part.

Recap + bridge: Counting binary digits halves the number at every step; the recurrence , is solved by assuming , which turns the closed form into , i.e., — and the correct term is basic operation, not "base operation." The next section steps back from individual algorithms to survey the solving methods available for recurrences — and explains why the substitution method is skipped for now.

Real-world connection: halving recursions are everywhere in computing — binary search on a sorted list, finding the height of a balanced tree, and the exponentiation-by-squaring used in cryptography all run in because each step discards half the input. This is why searching a database index with a billion rows takes about 30 comparisons ( ) rather than a billion — the same halving arithmetic as counting binary digits, applied by engineers who need to know whether a lookup stays fast as data grows.

3.8 The Methods for Solving Recurrences

3.8.1 The Menu of Methods

Hook: You have now solved recurrences three times — but each time by the same hand-cranked substitution drill. There are faster tools: a visual one (the recursion tree) and a near-instant one (the master method). This short section lays out the menu before the remaining examples.

There are several methods for solving recurrences: the iterative method (already used twice), the substitution method, and the recursion tree method. This session covers the iterative method and the recursion tree method; then comes the master method, the easiest of all.

The menu at a glance:

  1. Iterative method (used in 3.3, 3.5, 3.6): substitute the recurrence into itself repeatedly until a pattern appears, then close the pattern at the known base case. Strengths: works on any shape of recurrence, and it is the tool when the size decreases by a constant ( ). Weakness: the algebra grows tedious for halving recurrences.
  2. Recursion tree method (3.9): draw the recurrence as a tree — each node is one sub-problem's cost — sum the cost level by level, and add the levels. Strengths: visual, and it explains why the master method works. This session's remaining worked examples use it.
  3. Master method (3.10): a cookbook for recurrences of the form — compare against and read off the answer from one of three cases. Strengths: fastest of all; no tree drawing, no substitution algebra. Constraint: only for the divide-and-conquer form .
  4. Substitution method (skipped here — see 3.8.2): guess the answer, then prove the guess by induction. Powerful in advanced work, but it demands the guess up front.

3.8.2 Why the Substitution Method Is Skipped

The substitution method requires you to guess the time complexity first and then prove the guess. The problem: we do not even know what guess to make yet. The verdict is blunt — even if it were taught, it would not work at this stage — so the substitution method is skipped for now.

The reasoning is honest and practical: a method whose first step is "guess the answer" is unusable until you have built the intuition for what recurrences typically answer. That intuition comes from exactly the tools this session does teach — the iterative method's patterns and the recursion tree's picture. Reference texts describe the substitution method as a two-step dance (guess the bound, then verify by induction), and they freely admit the hard part is producing the guess — recursion trees are the standard trick for generating one. In this course, the guess-first method is deferred until the groundwork exists.

Recap + bridge: The methods for solving recurrences form a menu — iterative substitution (done twice), the recursion tree (next), and the master method (after that) — while the substitution method is deliberately skipped because it demands a guess we cannot yet make. The next section teaches the recursion tree: the visual method that will make the master method's three cases obvious.

Real-world connection: knowing which solving tool to reach for is itself a professional skill — engineers analyzing a divide-and-conquer routine reach straight for the master method, while a recursion that strips one element at a time (like a naive text-tokenizer) is unwound by iteration. Choosing the wrong tool wastes time; recognizing the recurrence's shape — constant shrink, halving, or divide-and-conquer — decides the tool, exactly as this menu does.

3.9 The Recursion Tree Method

3.9.1 The Idea of the Recursion Tree

Hook: The iterative method solved every recurrence so far, but each one needed fresh algebra. Is there a way to see the answer? Yes — draw the recurrence as a tree, where every node is one sub-problem's cost, and the total running time is just the sum of the whole tree.

In a recursion tree, each node represents the cost of a single sub-problem somewhere in the set of recursive function invocations. The term at the root represents the cost at the top level of recursion — the very first invocation.

Formalize — how a recursion tree is built. Take the recurrence . The is the cost of the first invocation apart from the recursive calls — exactly the role the +1 multiplication played in factorial. After the root cost, what remains are the recursive calls: three sub-problems of size , so the root has three children, each labeled . Each child expands by the same recurrence: becomes , and so on down the tree. The recipe in one sentence: each node's non-recursive cost is written on the node, its recursive calls become its children, and the recurrence is fully drawn when the sizes hit the base case. Reference texts state the same idea: in a recursion tree, each node represents the cost of a single subproblem somewhere in the set of recursive function invocations; we sum the costs within each level of the tree, then sum the level totals to get the total cost of all levels.

Does the tree stop? Yes — the sub-problem size shrinks at every level: , and so on, so sooner or later the size reaches 1, the base case. How far from the root is that? It is the height of the tree, and we can compute it — that computation is the first real calculation of the method.

3.9.2 Worked Example: Three Subproblems of Size n/4

Read the recurrence in words: a problem of size is divided into three sub-problems of size , and in every recursive call some basic operations run times.

Worked example — the recursion tree for .

Step 1 — nodes and sizes level by level. Number of nodes at each level: level 0 has 1 node (); level 1 has 3 nodes (); level 2 has 9 (); level 3 has 27 (); level has nodes.

Size of the sub-problem at each level: level 0 has size ; level 1 has size ; level 2 has size ; level 3 has size ; level has size .

Step 2 — the height. At height the size becomes 1, so:

This is where the familiar height formula comes from — it is derived, not memorized, and it depends on the divisor. If the size shrank by 2 every level, the height would be .

Step 3 — the leaves. Number of nodes at the last level:

by the logarithm rule . So the last level holds nodes, each costing 1 at the base case.

Step 4 — the cost at each level. The root costs . Each level-1 node costs , and there are three of them, so level 1 costs:

Level 2 costs , and level costs .

Step 5 — total time as a geometric series. Total time is the sum of the costs over all levels:

The geometric series has ratio , so the root term dominates:

Answer: . The answer was visible from the start — the root carries , the higher term — but you still compute the sum to confirm it. The sum in closed form is for the geometric part, plus the leaf cost ; since , the leaf term is asymptotically below , and the term wins. Sense-check: the level costs shrink by a factor each level, so the total is at most a constant multiple of the root cost — exactly the signature of an answer.

Q: Where does come from as the root cost?

A: It is the cost of the first invocation apart from the recursive calls — the same role the +1 multiplication played in factorial. The remaining costs are the three recursive calls .

Q: Why not squared over 16 at the root?

A: That value does appear — one level down. Each level-1 child costs , and the three children together sum to .

Q: Are we sure the tree ends?

A: Yes. The sub-problem size keeps shrinking — — so eventually the tree reaches the base case.

Q: How far from the root does the base case appear?

A: The height of the tree: the level at which the size reaches 1. The height comes out of the derivation — — not out of memorized formulas.

Q: How do we know the division is by 4? And what if the input size is not a multiple of 4?

A: The recurrence states it: a problem of size splits into sub-problems of size . For inputs that are not multiples of 4, the answer depends on the problem — that question gets handled when it comes up. (The standard practice, followed by the textbooks, is to ignore floors and ceilings: replacing by or does not change the asymptotic answer.)

Q: Will the exam ask for these big summations?

A: Understand the concepts first; exams are a later worry. The instructor does not like checking math skills in an algorithms exam.

3.9.3 Worked Example: Two Subproblems of Size n/2

Worked example — the recursion tree for . The recurrence appears when an algorithm splits a problem of size into two sub-problems of size and does work per invocation.

Step 1 — nodes and sizes. Root: cost . Two children, each of size . Each of those expands into two children of size — four nodes at level 2, and so on: level has nodes, each of size .

Step 2 — the height. The size reaches 1 at level :

Nodes at the last level:

Step 3 — the level costs. Cost at each level: level 0 costs ; level 1 costs ; level 2 costs ; the last level costs as well. So every level costs , and there are levels:

Answer: . This is the signature of merge-sort-like divide-and-conquer — the merge-sort recurrence has exactly this solution, . Sense-check: doubling adds one more level ( ) and doubles the per-level cost, so the total roughly doubles plus one level's worth — grows just slightly faster than linear, which is exactly what the formula says.

Q: Can we really say exactly ? is huge.

A: In this case the total is exactly , so theta is fine. In general, whenever bigger terms are around, write big-O of to be on the safer side — big-O also covers the equality case.

Q: Why not big-Omega here?

A: There is no clean answer; think about large values of and how we account for time. We can rarely pin a running time exactly — even at work, when running programs, we speak in approximations. It is always safer to give an upper bound: you would say "I might take ten minutes" rather than five when you might need seven. We only count the basic operation, so some slack always remains.

Q: Is an assumption?

A: just means constant time. It could be or — because is a very large value approaching infinity, the base case is a constant that does not involve the algorithm's complexity; it is solved directly.

Q: Why is equal to times ?

A: Because the tree has levels — the height — so the cost is added once per level, times.

Assumptions & scope: Both examples assume the input size is an exact power of the divisor (4 in the first tree, 2 in the second) so that every division stays whole — the standard, tolerable simplification in recurrence analysis; floors and ceilings do not change the order of growth. The tree method itself applies to any recurrence whose sub-problem sizes shrink by a fixed factor, and also to uneven splits (like in advanced texts) — there the tree is not full and the height is bounded by the slowest shrinking branch. What the method requires is the ability to sum the level costs; when the level costs form a geometric series with ratio the root dominates (first example), when the ratio is every level ties and the height decides (second example), and when the ratio is the leaves dominate — the three possibilities that the master method of the next section codifies.

Visual intuition: Draw the first tree as a triangle of nodes, one per level: the top node is a big square labeled , the next row has three smaller squares labeled each, then nine smaller still — the squares shrink by a factor of of the total row width, so the rows' total areas form the geometric series. Horizontal axis: the number of nodes per row (1, 3, 9, ...); vertical axis: the cost of each node (shrinking like ). The landmark: the root square is visibly bigger than all the rows below it combined. For the second tree, draw rows of squares where each row's total area equals the root's exactly — a "rectangle of height and width ". One-sentence takeaway: who wins — root, leaves, or a tie — is decided by whether the per-level costs shrink, grow, or stay constant down the tree.

Pitfalls:

  1. Forgetting that each level- node's cost shrinks too. A level- node in the first tree costs , not — multiplying the node count by the full would wrongly give -style series and a wrong answer.
  2. Miscounting the leaves. The leaves number , which is not or anything similar — the exponent must be read off the logarithm identity .
  3. Stopping at "the root dominates." The professor's point stands: the answer may be visible from the start, but you still sum the series to confirm it — the exam question is the sum, and shortcuts that skip it cannot be trusted.
  4. Using the tree for recurrences that do not divide. For the "tree" is a single chain — the tree method adds nothing there; pick the iterative method for constant-shrink recurrences and the tree (or master method) for division-shrink recurrences.

Recap + bridge: The recursion tree turns a recurrence into a picture: nodes are sub-problem costs, level totals are summed, and the answer is root-dominated (geometric ratio , here), leaf-dominated, or a tie across equal levels ( here). The next section extracts a cookbook from exactly this picture — the master method, which answers by comparing with , the root cost against the leaf cost.

Real-world connection: the tree is the shape of every good sorting algorithm (merge sort, heap sort) and of the balanced divide-and-conquer routines in database sort-merge joins — which is why sorting a billion records costs about 30 billion comparisons, not a billion-squared. The first tree's "root dominates" outcome is the shape of quicksort's worst case avoided and of unbalanced recursive splits in distributed computation, where one heavy top-level merge swallows the whole budget. Engineers who see their recursion profile as a tree know instantly whether the top level, the middle levels, or the leaves are eating the time — the same three-way diagnosis the master method formalizes.

3.10 The Master Method

3.10.1 The General Form

Hook: After the recursion tree, solving recurrences is still a small ritual of drawing and summing. The master method replaces the whole ritual with three if-this-then-that rules — read the recurrence, compare two functions, write the answer. It is the tool working engineers actually use.

The master method applies to recurrences of the form:

Formalize — reading the form. Read in English: a problem of size is divided into sub-problems of size each, and the cost of the first invocation — the work done apart from the recursive calls — is . The parameters must satisfy (a problem must split into at least one sub-problem) and (the sub-problem size must shrink).

Everything needed falls out of the recursion tree picture: the level costs are , and so on; the height of the tree is ; and the number of leaf nodes is .

Q: How do we read in English?

A: A problem of size is divided into sub-problems of size each, and the cost of the first invocation is — some processing that runs for time in each invocation.

The master method is the one to use all the time — it is the easiest, and there is no time to waste drawing trees or iterating. Why was it not taught first? Because its terms — , , and — would have meant nothing without the recursion tree background. Now they mean something.

3.10.2 The Three Cases

Case 1 — the leaves win: for some . Here grows polynomially slower than , so the leaves dominate:

Case 2 — a tie, settled by a log factor: . The two functions grow at the same rate, so neither dominates; a log factor is added:

Case 3 — the root wins: for some . Here grows polynomially faster, so the root dominates:

with one extra condition: the regularity condition must hold for some constant . That check is required before writing the case-3 answer.

The concept behind all three cases: compare the cost at the root, , with the cost at the leaves, . Whichever is larger decides the solution. The catch: the comparison must be polynomial, not merely asymptotic — look at the highest power of , not just the growth rate. (This is why loses to in case 1 but is not "polynomially larger" than : its power of is only 1.)

3.10.3 Worked Examples

Example 1 — . Here , , . Compute first:

and are both — equal. That is case 2:

Answer: . Same answer the recursion tree gave, in a fraction of the steps — and the theta is now fully justified, which clears the earlier big-O-versus-theta doubt. Sense-check: the recurrence is merge sort's recurrence, whose known answer is — the master method reproduces it instantly.

Example 2 — . Here , , :

because squared is larger than . Since is larger than , grows polynomially slower than — case 1:

Answer: . Sense-check: nine sub-problems of size with linear combine-work: the sub-problems alone produce -sized work at the leaves ( leaves), so a quadratic answer is exactly what the tree picture predicts.

Example 3 — . Here , , . We need , and we do not need its exact value — only that (4 to what power gives 3? Less than , so less than 1). So grows more slowly than — case 3. Check the regularity condition:

holds for a suitable , so:

Answer: . Sense-check of the regularity check: with , the left side is less than (since ), so the condition holds — and the tree's level costs are a geometric series with ratio , so the root term really does dominate.

3.10.4 The Generalization of Case 2

Example 4 — . Here , , , and:

Now compare: is asymptotically larger than , but the highest power of in both is 1 — they grow at the same rate up to a log factor. So none of the three standard cases applies cleanly: the functions are not polynomially separated.

There is a generalization for exactly this situation, found in only a few books and carried in the course notes — it is not in the prescribed textbook. If:

then:

For example 4, :

Q: How is equal to in the general case?

A: That was a slip in the write-up — it must be . With the exponent becomes , which is how the answer came out as log square. Thanks for pointing it out.

Assumptions & scope of the method: The master method applies only to the divide-and-conquer form with constants , , and an asymptotically positive . It does not apply when the three cases leave a gap: if is smaller or larger than but not polynomially so (the versus gap above, or an versus situation), none of the cases matches and the method is silent — the recursion tree or a generalization is needed. Case 3 additionally demands the regularity check ; nearly every polynomially bounded passes it, but the check must still be written before the answer. Also, floors and ceilings on are ignored by the standard statement: replacing by or does not change the asymptotic result.

3.10.5 The Concept Behind the Cases

All three cases depend on one comparison: against . Conceptually, is the cost incurred at the root of the recursion tree, and is the cost incurred at the leaves. The larger of the two decides the solution. But polynomial growth is the catch — you look at the power of , not just asymptotic growth — and case 3 carries the regularity check.

No need to memorize the three cases: by this point the concept is understood, and understanding beats memorization.

Q: Do we have to memorize the three cases?

A: No. Understand the comparison between the root cost and the leaf cost , remember the regularity check for case 3, and the cases follow.

Visual intuition: Recall the two recursion trees of 3.9. The three cases are the three possible shapes of the level-cost series: case 1 is a shrinking geometric series (each level costs less than the one above — leaves win, height of the leaf pile decides); case 2 is a flat series (every level ties, so the total is the per-level cost times levels); case 3 is a growing series (the root's dwarfs everything below). Plot the level costs on the vertical axis against level number on the horizontal axis: the three curves are a downward slide, a flat line, and an upward ramp. One-sentence takeaway: find which of root, leaves, or both-equal decides the tree, and the case — and the answer — follow.

Pitfalls:

  1. Comparing asymptotics instead of powers of . is asymptotically "bigger" than but has the same power of — that is a gap, not case 3. Case 3 needs a polynomial gap: , i.e., a higher power of .
  2. Writing case 3 without the regularity check. The professor's explicit rule: check for some before writing the case-3 answer.
  3. Forgetting the log factor in case 2. A tie is not "either function" — the answer is the tied value times one extra log factor.
  4. Using the master method outside its form. It only covers . Recurrences with terms (factorial, Hanoi), with two different sub-problem sizes, or in the gaps between cases need the iterative method or the recursion tree instead.
  5. Trusting a slip without checking. The typo was caught by a student asking "how is equal to ?" — when your answer's algebra reads oddly, re-derive it rather than copy it.

Exam note: No need to memorize the three cases — but you must be able to compare with (as functions of the power of ) and to apply the regularity check in case 3. Understanding the root-versus-leaves comparison beats memorization.

Recap + bridge: The master method answers by comparing the root cost against the leaf cost : polynomially smaller gives case 1 (), equality gives case 2 (), polynomially larger with the regularity check gives case 3 (); the log-power generalization handles with . With the iterative method, the recursion tree, and the master method all in hand, the session's toolkit for solving recurrences is complete — the closing appendices summarize what the quiz expects and what these running times mean in industry.

Real-world connection: the master method is the everyday tool for sizing divide-and-conquer systems before they are built — a database engineer checking a balanced-split join (case 2, ), a search team checking a 9-way split index (case 1, — the signal to stop splitting), or a distributed merge with heavy combine cost (case 3, the combine term decides). Knowing which case a recurrence falls into is how engineers predict whether doubling data doubles, quasi-doubles, or quadruples the runtime — the same three curves as the recursion-tree shapes, read off in seconds.

Exam Guidance Summary

  • Time calculations will be asked in the quiz. This was stressed more than once, and the quiz comes after session four. Practice writing recurrences and solving them (iterative method, recursion tree, master method) until the steps are routine.
  • The quiz runs for one hour and stays open for several days (per the instruction cell's calendar); the date, topics, and window will be announced. Once started, it must be completed in one go.
  • Terminology is graded: "base operation" earns zero for that term; the correct term is "basic operation."
  • The basic operation is the statement executing the maximum number of times; in a recursive algorithm, look in the recursive part, not the base case.
  • No need to memorize the three master-method cases — but you must be able to compare with (as functions of the highest power of ) and apply the regularity check in case 3.
  • Textbook advice: Goodrich is enough for preparation. After the basic understanding is in place, open Cormen — it will sound like Greek and French at first, but read it twice or thrice and it clicks.
  • Refresh your math: logarithms, arithmetic progressions, geometric progressions (including the GP sum formula) — these power the solutions.
  • Concepts before computation: the instructor does not like checking math skills in an algorithms exam, so understand the ideas behind the summations (the recursion-tree picture, the root-versus-leaves comparison) rather than memorizing sums.
  • Homework exercises were posted; work them and post your solutions in the discussion forum. A case study for the master method is also for you to go through.
  • Assignment 1 and 2 roll out together about fifteen days out: individual work, two questions, and questions may come from post-mid-semester topics too. Start early; the material will be covered in due course — no need to panic when the questions first appear.

Exam note: the single most examinable skill from this session is the time calculation: pick the size parameter, identify the basic operation, write the two-case recurrence, solve it, and state the order of growth. The terminology points ("basic operation", never "base operation") and the master-method comparison skill are the other two things the quiz checks.

Key Industry Applications

Real-world: when you are running an algorithm or a program at work, you rarely state an exact running time — you give an approximation, and it is always safer to give an upper bound ("I might take ten minutes" rather than five). This is the same reasoning that prefers big-O in analysis: some slack always remains because only the basic operation is counted. In practice this is how engineers set capacity expectations: when a service owner is asked "how long will this batch job take?", the honest answer is an upper-bound estimate computed from the order of growth — for a one-pass job, for a sort, for something exponential — because exact constants depend on hardware, compiler, and input distribution that are never known precisely at planning time.

Real-world: exponential time complexity means the algorithm performs on the order of computations even for relatively small or 15 is already expensive. For some problems, like Tower of Hanoi, no better algorithm is known, and the problem itself must be accepted as computationally expensive; but whenever a linear-time algorithm exists for a problem, it is the one to write. In industry, this is the difference between a product feature that ships (linear or scans over records) and one that dies in review (an exponential recursion over inputs of size 30+): the recurrence analysis done in this session is the same arithmetic used to reject exponential designs before they are built — and the same arithmetic that justifies accepting them when the problem's nature leaves no faster route (for example, certain search and optimization problems where the exponential algorithm is the known best).

DSA Lecture 3 notes · Analyzing Recursive Algorithms

Data Structures and Algorithms· postgraduate· 2026-08-09

Sections Breakdown

13.1 Recursion and the Base Case

What recursion really means — a procedure calling itself on strictly smaller sub-problems — and the base case that stops the call chain.

23.2 Recursive Maximum: The First Worked Example

The recursive maximum-finding algorithm, read line by line, with a full hand trace on a concrete array.

33.3 Recurrence Equations and the Iterative Method

Writing a recursive algorithm's running time as a two-case recurrence and solving it by repeated substitution to a closed form.

43.4 The General Plan and the Shift to Basic Operations

The five-step plan for analyzing any recursive algorithm, and the switch from primitive operations to the single basic operation.

53.5 Factorial: Basic Operations in Action

Factorial's multiplication-based recurrence T(0)=0, T(n)=T(n-1)+1 solved to exactly n, giving Theta(n).

63.6 Tower of Hanoi

The classic three-step recursive solution and its recurrence M(n)=2M(n-1)+1, closed with a geometric-progression sum to 2^n - 1.

73.7 Counting Binary Digits

A halving recursion analyzed under the power-of-two assumption, giving A(n) = log2 n = Theta(log n), and the correct term: basic operation.

83.8 The Methods for Solving Recurrences

The menu of solving methods — iterative, recursion tree, master — and why the substitution method is deferred.

93.9 The Recursion Tree Method

Drawing a recurrence as a tree of sub-problem costs: heights, leaf counts, and level-cost sums for 3T(n/4)+cn^2 and 2T(n/2)+n.

103.10 The Master Method

The three cases of the master method for T(n)=aT(n/b)+f(n), the regularity check, and the case-2 generalization with log powers.

11Exam Guidance Summary

The exam-facing summary of the session: quiz timing, graded terminology, and the skills the quiz checks.

12Key Industry Applications

How upper-bound running-time estimates and recurrence analysis decide what ships in real systems.

Postgraduate students learning to analyze recursive algorithms

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Recursion and the Base Case

Must-know: Every recursive algorithm has two parts: a base case (smallest instance, answered directly) and an otherwise case (recursive call on a strictly smaller sub-problem); the shrinking is what guarantees the recursion stops.

Top pitfall: Forgetting the base case or recursing on the same size instead of a smaller size causes infinite recursion; also do not confuse 'base case' with 'basic operation'.

Self-check: Why must every recursive call work on a strictly smaller input size?

Connects to: 3.2

Recursive Maximum: The First Worked Example

Must-know: recursiveMax(a,n) = max(recursiveMax(a,n-1), a[n-1]) with base case return a[0] when n=1; trace by expanding calls down to the base case, then unwinding values back up.

Top pitfall: Evaluating max before the recursive call's value is known, or thinking each call re-scans the whole array.

Self-check: What is the base case of recursiveMax and what does it return?

Connects to: 3.1, 3.3

Recurrence Equations and the Iterative Method

Must-know: Write the recurrence with two cases (constant base case, recursive term plus per-level work), then solve by repeated substitution: T(n)=T(n-1)+7 gives T(n)=7n-4=O(n).

Top pitfall: Closing the general form at T(0), which the recurrence never defines; stop at the known base case (i = n-1 here).

Self-check: After i substitutions, what is the general form of T(n) = T(n-1) + 7, and which i closes it?

Connects to: 3.2, 3.4, 3.5

The General Plan and the Shift to Basic Operations

Must-know: The five-step plan: (1) size parameter n, (2) count executions of the basic operation, (3) base case, (4) recurrence, (5) solve and state asymptotics. The basic operation is the statement executing the maximum number of times; in recursive algorithms it lives in the recursive part, not the base case.

Top pitfall: Looking for the basic operation in the base case, or counting all primitive operations instead of the single dominating statement.

Self-check: Where do you look for the basic operation in a recursive algorithm?

Connects to: 3.3, 3.5, 3.7

Factorial: Basic Operations in Action

Must-know: Basic operation of factorial is the multiplication; T(0)=0, T(n)=T(n-1)+1 solves to exactly n, hence Theta(n). The base case's value is 0 because no multiplication happens there.

Top pitfall: Guessing the base case from the return value (1 or 2) instead of the basic-operation cost (0), or counting the recursive call itself as an extra operation.

Self-check: After i substitutions, T(n) = i + T(n-i); why is i = n the right stopping point here?

Connects to: 3.3, 3.4, 3.6

Tower of Hanoi

Must-know: M(1)=1, M(n)=2M(n-1)+1; after i expansions M(n)=2^i M(n-i)+(2^i-1); the tail is a GP with first term 1 and ratio 2 summing to 2^i-1; with i=n-1 the closed form is M(n)=2^n-1=O(2^n). The +1 is a real move of the largest disk.

Top pitfall: Dropping the +1 (it pays for moving the largest disk, unrelated to the base case) or failing to recognize the tail as a geometric progression.

Self-check: Why does the tail 1+2+4+...+2^(i-1) sum to 2^i - 1?

Connects to: 3.3, 3.5, 3.9

Counting Binary Digits

Must-know: Basic operation is the halving; A(1)=0, A(n)=A(n/2)+1. Assume n=2^k, then A(2^k)=A(2^(k-i))+i, close at i=k with A(1)=0 to get A(2^k)=k; convert back to A(n)=log2 n = Theta(log n). Term on the exam: basic operation, never 'base operation'.

Top pitfall: Writing 'base operation' instead of 'basic operation' (cut to zero), or leaving the answer as k instead of converting back to log2 n.

Self-check: Why is A(1)=0 under the basic-operation method?

Connects to: 3.4, 3.9

The Methods for Solving Recurrences

Must-know: Four methods exist: iterative, substitution (skipped — it needs a guess first), recursion tree, and master method (the easiest).

Top pitfall: Trying the substitution method without being able to guess the answer; the professor defers it for exactly this reason.

Self-check: Why is the substitution method skipped in this session?

Connects to: 3.3, 3.9, 3.10

The Recursion Tree Method

Must-know: Tree height comes from n/b^H = 1, so H = log_b n; level i has a^i nodes of size n/b^i; leaves number n^(log_b a). If level costs form a geometric series with ratio < 1 the root dominates (3T(n/4)+cn^2 gives O(n^2)); if every level costs the same, total is level cost times log n levels (2T(n/2)+n gives Theta(n log n)).

Top pitfall: Forgetting that each level-i node's cost shrinks to c(n/4^i)^2; or concluding 'root dominates' without summing the series.

Self-check: Why is the height of the tree for T(n)=3T(n/4)+cn^2 equal to log4 n?

Connects to: 3.10, 3.7

The Master Method

Must-know: For T(n)=aT(n/b)+f(n) with a>=1, b>1: compute n^(log_b a); f polynomially slower -> case 1 Theta(n^(log_b a)); equal -> case 2 Theta(n^(log_b a) log n); polynomially faster + regularity af(n/b)<=cf(n), c<1 -> case 3 Theta(f(n)). Generalization: f(n)=Theta(n^(log_b a) log^k n) gives Theta(n^(log_b a) log^(k+1) n).

Top pitfall: Calling n log n 'bigger' than n is not case 3 — the gap must be polynomial (a higher power of n); and case 3 requires the regularity check before writing the answer.

Self-check: Which case applies to T(n)=9T(n/3)+n and why?

Connects to: 3.9, 3.3

Exam Guidance Summary

Must-know: Quiz after session four, one hour, completed in one go; time calculations will be asked; terminology graded; Goodrich enough for preparation, Cormen after; refresh logarithms, APs and GPs including the GP sum formula.

Top pitfall: Writing 'base operation' instead of 'basic operation' earns zero for that term.

Self-check: Which textbook is enough for preparation and which is recommended after basic understanding?

Key Industry Applications

Must-know: Give an upper-bound estimate of running time at work (like big-O); write the linear algorithm whenever one exists; accept exponential only when no better algorithm is known.

Top pitfall: Claiming only an exponential-time algorithm exists when a linear one does.

Self-check: Why is it safer to give an upper bound for a running time estimate?

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.