Recursion is a problem-solving technique where a function calls itself to break a complex problem down into simpler subproblems. Think of a set of nested dolls: each doll contains a smaller version of itself until you reach the smallest one, the base case.
Recursion has two essential pieces: the base case and the recursive case. The base case is what stops the recursion (without it, you get an infinite loop). The recursive case is where the function calls itself with a modified argument, gradually moving toward the base case.
This technique shows up in tree traversals, the Fibonacci sequence, and divide-and-conquer algorithms in general, where each recursive call peels off a smaller piece of the original problem.
Each recursive call creates a new execution context on the call stack. The function does some work, then calls itself with a new argument that represents a smaller piece of the original problem. When the base case is finally reached, the function stops calling itself and starts returning values, unwinding the call stack in reverse order.
Think of it as descending into the layers of a problem until you hit the simplest case, then working your way back up by combining the results of each recursive call. You need a clear termination condition. Without a proper base case, recursion runs forever and overflows the stack.
Recursion often leads to clean, compact solutions, but it uses more memory because every call sits on the stack. For deep recursion, consider memoization to avoid redundant work, or convert the recursion into an iterative loop when stack depth becomes a problem.
Recursion fits naturally on problems with a hierarchical structure, like tree and graph traversals, and on backtracking algorithms. Spotting when a problem can be broken into similar subproblems is most of the battle. As you solve more recursive problems, you'll start to see patterns that help you decide between a recursive and an iterative approach.
Recursion is one of the patterns that rewards careful planning: the base case, the recursive case, the stack budget, and any memoization. Test thoroughly so your recursive functions handle every input gracefully, including the edge cases.
Recursion clicks once you stop tracing the call stack and start trusting the recursive contract: "this function returns X for any subproblem." Work through these to internalize divide-and-conquer, recursive matching with memoization, and the recursive structure that underlies linked-list and tree problems:
Completed | Title | Status | Notes | Solution | |
|---|---|---|---|---|---|
Easy | |||||
Easy | |||||
Easy | |||||
Easy | |||||
Medium | |||||
Medium | |||||
Medium | |||||
Medium | |||||
Hard | |||||
Hard | |||||
Hard | |||||
Hard |