Skip to main content
Recursion Pattern

What is Recursion?

Recursion is when a function calls itself to solve smaller instances of the same problem. Every recursive solution has a base case (termination) and a recursive case (breakdown).
Quick Recognition: Problems that can be broken into smaller self-similar subproblems. Look for: tree/graph traversal, nested structures, divide and conquer.

Pattern Recognition Checklist

Use Recursion When

  • Tree/graph traversal (DFS)
  • Nested or hierarchical structures
  • Divide and conquer algorithms
  • Backtracking problems
  • Mathematical sequences (factorial, fibonacci)
  • Subproblems have same structure as original

Don't Use When

  • Simple iteration suffices
  • Large input (stack overflow risk)
  • No natural subproblem structure
  • Tail recursion can be converted to loop

Recursion Types

TypeDescriptionExample
LinearOne recursive callFactorial, sum of array
BinaryTwo recursive callsFibonacci, binary tree
MultipleMany recursive callsN-ary tree traversal
MutualFunctions call each otherEven/odd check
NestedRecursive call in argumentAckermann function
TailRecursive call is last operationOptimizable to iteration

The Three Laws of Recursion

  1. A recursive function must have a base case
  2. A recursive function must change state toward the base case
  3. A recursive function must call itself

When to Use

Tree/Graph Traversal

DFS, preorder, inorder, postorder

Divide and Conquer

Merge sort, quick sort

Backtracking

Permutations, combinations

Dynamic Programming

Top-down memoization

The Recursive Template

def recursive_function(problem):
    # Base case(s) - when to stop
    if is_base_case(problem):
        return base_solution
    
    # Recursive case - break down and solve
    smaller_problem = reduce(problem)
    sub_result = recursive_function(smaller_problem)
    
    # Combine results
    return combine(sub_result, current_work)

Pattern Variations

1. Simple Recursion (Factorial)

def factorial(n):
    """Base case + single recursive call"""
    if n <= 1:
        return 1
    return n * factorial(n - 1)

2. Tree Recursion (Fibonacci)

def fibonacci(n, memo={}):
    """Multiple recursive calls (memoized)"""
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
    return memo[n]

3. Tail Recursion

def factorial_tail(n, acc=1):
    """Last operation is recursive call - can be optimized"""
    if n <= 1:
        return acc
    return factorial_tail(n - 1, n * acc)

4. Helper Function Pattern

def solve_problem(input_data):
    """Public API, calls recursive helper"""
    result = []
    
    def helper(state, index):
        if is_complete(state):
            result.append(state[:])
            return
        
        for choice in get_choices(index):
            state.append(choice)
            helper(state, index + 1)
            state.pop()
    
    helper([], 0)
    return result

5. Binary Tree Traversal

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def inorder_traversal(root):
    """Left -> Root -> Right"""
    if not root:
        return []
    return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)

def max_depth(root):
    """Height of binary tree"""
    if not root:
        return 0
    return 1 + max(max_depth(root.left), max_depth(root.right))

Classic Problems

ProblemPatternKey Insight
FactorialSimpleOne recursive call
FibonacciTree + MemoMultiple calls, cache results
Tower of HanoiMutualMove n-1, move 1, move n-1
Tree TraversalBinaryLeft subtree, root, right
PermutationsBacktrackChoose, explore, unchoose

Common Mistakes

Avoid These Pitfalls:
  1. Missing base case: Leads to infinite recursion and stack overflow
  2. Base case never reached: State doesn’t progress toward termination
  3. Wrong return value: Not combining subproblem results correctly
  4. Modifying shared state: Forgetting to backtrack in backtracking
  5. Stack overflow: Too deep recursion without memoization or tail call

Debugging Recursion

1

Verify Base Case

Is there at least one base case? Does it return correct value?
2

Check Progress

Does each recursive call move toward the base case?
3

Trace Small Input

Manually trace with n=0, n=1, n=2 to verify logic
4

Add Print Statements

Print entry/exit to visualize call stack
5

Consider Memoization

If same subproblems repeat, add caching

Interview Problems by Company

ProblemCompanyKey Concept
FibonacciAllBinary recursion + memo
Reverse StringAmazonTwo-pointer recursion
Merge Two ListsAll FAANGLinked list recursion
Maximum Depth of TreeAllBinary tree recursion

Interview Tips

Script for interviews:
  1. “I’ll solve this recursively because it breaks into smaller self-similar subproblems.”
  2. “My base case is [describe when to stop].”
  3. “My recursive case [describe how to break down].”
  4. “I combine results by [describe combination].”
  5. “Time complexity is O(X) because [reasoning].”
AspectRecursionIteration
ReadabilityOften cleaner for treesBetter for simple loops
MemoryStack framesUsually O(1)
PerformanceFunction call overheadGenerally faster
When to chooseComplex branchingSimple linear process
Many recursive solutions can use explicit stack:
# Recursive
def preorder(root):
    if not root:
        return []
    return [root.val] + preorder(root.left) + preorder(root.right)

# Iterative with stack
def preorder_iterative(root):
    if not root:
        return []
    result, stack = [], [root]
    while stack:
        node = stack.pop()
        result.append(node.val)
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)
    return result

Practice Problems

Practice Roadmap

1

Day 1: Basic Recursion

  • Solve: Fibonacci, Factorial, Sum of Array
  • Focus: Base case + recursive case pattern
2

Day 2: Tree Recursion

  • Solve: Max Depth, Same Tree, Invert Tree
  • Focus: Binary tree traversal patterns
3

Day 3: Divide and Conquer

  • Solve: Pow(x, n), Merge Sort
  • Focus: Splitting and combining
4

Day 4: Advanced Recursion

  • Solve: Decode String, Regular Expression
  • Focus: Complex nested structures
Interview Tip: If you’re stuck on recursion, start by asking: “What’s the smallest version of this problem I can solve directly?” That’s your base case.