Skip to content
Skilled.dev

Recursion | Coding Interview and Computer Science

Trace recursive execution, define a smaller subproblem, and connect base cases and return values to a clear correctness argument.

14:31 · Trey Huffine · Published 2025-10-15

Watch on YouTube · Read lesson notes · Open the current lesson

Chapters

  1. 0:00 Introduction
  2. 0:15 Definition
  3. 1:07 Comparing Iterative and Recursive Algorithms
  4. 7:46 Stack Overflows
  5. 8:53 Code Walkthrough

Selected start: 0:00. Press play in the video to watch.

Changes since recording

  • The iterative flatten now puts nested items at the front of its queue, so it keeps the original order: [1, [2, 3], 4] becomes [1, 2, 3, 4].
  • Tail-call optimization only applies to a call in tail position. Python doesn't implement it, and among JavaScript engines only Safari's does.

Use the current lesson code when checking behavior.

Lesson notes

These notes explain the problem and current implementation. They are a reading companion, not a verbatim transcript of the recording.

A recursive function solves a problem through smaller calls to the same function. Each call needs enough local state to finish after its child returns. The recording uses examples to connect that control flow with the call stack. Understanding the saved work makes it easier to choose a base case and to translate a recursive solution into an iterative one.

State what one call promises

For factorial on nonnegative integers, one call returns the product from 1 through its argument, with factorial of zero equal to 1. A recursive step reduces the argument by one and multiplies by the returned smaller answer. That argument reaches the base case, so the chain terminates. A function that calls itself without making progress can exhaust its stack even if its syntax looks plausible.

Trace a small call with separate lines for entering and returning. Factorial of 3 first waits for factorial of 2; the multiplication by 3 happens after the smaller call finishes. That pending multiplication explains why this form needs stack frames and why its recursive call is not in tail position.

Preserve order when replacing the stack

Flattening nested arrays is another useful trace. For [1, [2, 3], 4], depth-first expansion should produce [1, 2, 3, 4]. An iterative replacement must put pending nested work in the right place. Appending every discovered child to a FIFO queue can process 4 before 2 and 3. Compare the order of unfinished work with the recursive version before claiming equivalence.

The flattening guide uses an explicit stack and discusses holes, shared branches, and cycles. Those extra contracts matter for general input. A finite nested-array example does not establish that a traversal can handle a self-referential structure.

Count depth as well as calls

Time depends on how many calls execute and what each call does. Peak stack space depends on the longest active chain. A branching recursion may execute exponentially many calls while having only linear depth. Repeated subproblems may benefit from memoization, but recursion alone does not imply dynamic programming.

Use the recursion tool to follow pending frames. Then try Sum Digits and explain both its reduction step and the storage used for an input with many digits.

More in Recursion