TweakCode
Recursion lessons

Recursion · Stage 1 of 3

Call Stack & Base Cases

Break a problem into a smaller self-call plus a stopping condition

Foundations

A recursive function solves a problem by calling itself on a smaller version of the same problem. Each call gets a frame on the call stack holding its own arguments, and frames leave in last-in, first-out order, just like the pushes and pops of the Stack lesson: a call that makes another call waits until it returns. A base case is an input small enough to answer directly; without one, frames pile up until the program crashes.

Writing recursion takes a leap of faith: assume the call on the smaller input already returns the right answer, and decide only how to finish the current call with it. Then check that every chain of smaller calls reaches a base case. Each frame does a little work on the way down, to set up its smaller call, and a little on the way back, to combine.

Sum nums = [7, 1, 5, 3, 6] recursively: total(nums) returns nums[0] + total(nums[1:]), and the base case total([]) returns 0. The calls stack six frames deep, from total([7, 1, 5, 3, 6]) down to total([]); then the answers return upward: 0, 6, 9, 14, 15, and finally 22.

  1. total([7, 1, 5, 3, 6])waiting
  2. total([1, 5, 3, 6])waiting
  3. total([5, 3, 6])calling
  4. total([3, 6]) = 9returned
  5. total([6]) = 6returned
  6. total([]) = 0returned
The base case, total([]), returned 0 without another call. Answers then flowed back up, 6 and then 9. Now total([5, 3, 6]) adds 5 + 9 while the first two calls still wait.
  • Stack

    Each call waits on the call stack until the calls it made return. That lesson covers push and pop.

    Open lesson

Case Scenario

The problem

K-th Symbol in Grammar

Row 1 is 0. Each 0 becomes 01 and each 1 becomes 10 to form the next row. Return the kth symbol (1-based) in row n. Do not build the whole row.

Input
n = 4, k = 5
Output
1

K-th Symbol in Grammar builds rows from "0": each row replaces every 0 with 01 and every 1 with 10, and the question asks for position k of row n. That position was written by position (k + 1) // 2 of the row above, a smaller call, and row 1 is the base case. For n = 4 and k = 5, the chain climbs through rows 3, 2, and 1 and returns 1.

The direct approach builds every row from "0" up to row n, then reads position k. Each row is twice as long as the one before, so row n holds 2ⁿ⁻¹ symbols: 8 here, but over 500 million by row 30, all built to read a single position.

Approach 1 · Brute force

Build every row

Start from "0" and expand each row, replacing 0 with 01 and 1 with 10, until row n exists, then read index k - 1.

Time O(2ⁿ) · Space O(2ⁿ)

  1. 1def kthGrammar(n, k):
  2. 2 row = "0"
  3. 3 for _ in range(n - 1):
  4. 4 row = "".join("01" if ch == "0" else "10" for ch in row)
  5. 5 return int(row[k - 1])

Approach 2 · Follow the parents

Walkthrough

Same input, now one step at a time. Each frame highlights the line that runs and the values it changes.

  1. 1.If n is 1, return 0.
  2. 2.Find the parent: position (k + 1) // 2 in row n - 1, by a recursive call.
  3. 3.If k is odd, return the parent. If k is even, return 1 - parent.

Python

K-th Symbol in Grammar

Input:
n = 4, k = 5
Output:
1
  1. 1def kthGrammar(n, k):
  2. 2 if n == 1:
  3. 3 return 0
  4. 4 parent = kthGrammar(n - 1, (k + 1) // 2)
  5. 5 if k % 2 == 1:
  6. 6 return parent
  7. 7 return 1 - parent

row 1

0
0

row 2

01
0
1

row 3

0123
0
1
1
0

row 4

01234567
0
1
1
0
1
0
0
1

Position 5 of row 4 was written by position (5 + 1) // 2 = 3 of row 3. Ask for that one and trust the answer.

1 / 8

The Pattern

The invariant: kthGrammar(n, k) returns the right symbol for every smaller row, so each call trusts its parent's answer and only copies it, for odd k, or flips it, for even k. Every chain of calls drops one row and ends at row 1, the base case.

From the trace

K-th Symbol in Grammar

row 1

0
0

row 2

01
0
1

row 3

0123
0
1
1
0

row 4

01234567
0
1
1
0
1
0
0
1
k = 5 is odd, the first of its pair, so it copies its parent: 1.

Check it against the walkthrough. Position 5 of row 4 came from position (5 + 1) // 2 = 3 of row 3, which came from 2 in row 2, then 1 in row 1, the base case, 0. Returning, row 2's even position flipped 0 to 1, and rows 3 and 4, both odd positions, copied it: 1.

Four frames waited on the stack, one per row, and no row was ever built. That shape, one smaller call plus a stopping condition, is all recursion needs. Choosing the smaller call, and trusting its answer, is the whole design.

Complexity

TimeO(n)

SpaceO(n)

There is one call per row, each with O(1) work, so time is O(n). The calls wait on the stack until row 1 answers, so space is O(n). Building the rows costs O(2ⁿ) time and memory: row 30 alone has over 500 million symbols.

Brute force

Build every row

O(2ⁿ) time

O(2ⁿ) space

This technique

Follow the parents

O(n) time

O(n) space

1k
10
1M
20
1.1B
30

n=10

n=20

n=30

Build every rowFollow the parents

Symbols written versus calls made, log scale.

When to use this in an interview

  • The input contains a smaller copy of itself, such as a subtree, the rest of a list, or the previous row.
  • The answer for n can be written from the answer for a smaller n.
  • A clear smallest case can be answered directly.

In production

Recursive descent parsers

Compilers such as GCC and Clang parse source code by recursive descent: each grammar rule is a function, a rule like expression calls the functions for the smaller pieces inside it, and a literal or a name is a base case that returns at once. Every nested parenthesis adds a frame, which is why absurdly nested input can overflow a parser's stack. Like the walkthrough, each call trusts the smaller calls to return a correct result.

Where this breaks

One parent chain reaches row 1 because each symbol has one parent. A value that depends on a whole row cannot be found that way.

Your turn

Solve it yourself

You have watched each call trust a smaller one. Write it yourself on K-th Symbol in Grammar, then recurse on the rest of a list in Swap Nodes in Pairs, and on inner lists in Nested List Weight Sum.

  1. 1

    K-th Symbol in Grammar

    Guided · the problem you traced above

    Solve it
  2. 2Swap Nodes in PairsOn your own · same pattern, no walkthrough
  3. 3Nested List Weight SumOn your own · same pattern, no walkthrough

Finished this lesson?

Mark it complete when you are ready to move on.