Pattern #20
Recursion
Important interview questions, thinking patterns, base cases, call stack mechanics, and rules for solving recursive problems in Go.
Must Solve
18 core questions — solve these first.
- 1.FactorialBase n <= 1, return n * factorial(n-1)easy
- 2.Fibonacci NumberBase n <= 1, fib(n-1) + fib(n-2)easy
- 3.Pow(x, n)Divide & Conquer exponentiation by halvingmedium
- 4.Reverse StringSwap outer chars recursivelyeasy
- 5.Palindrome CheckBase len <= 1, check S[0] == S[len-1]easy
- 6.Binary Search using RecursionDivide range mid +/- 1easy
- 7.Merge Two Sorted ListsRecursive list mergingeasy
- 8.Reverse Linked Listhead.Next.Next = head; head.Next = nileasy
- 9.Maximum Depth of Binary Tree1 + max(depth(Left), depth(Right))easy
- 10.Same Treep.Val == q.Val && isSame(Left) && isSame(Right)easy
- 11.Invert Binary TreeSwap Left & Right children recursivelyeasy
- 12.Path SumSubtract val from targetSum down to leafeasy
- 13.Generate ParenthesesBacktracking recursion open/close countmedium
- 14.SubsetsInclude / exclude recursion treemedium
- 15.PermutationsSwap / visited backtracking recursionmedium
- 16.Combination SumChoose element multiple times recursionmedium
- 17.Letter Combinations of a Phone NumberDigit index string mapping recursionmedium
- 18.Word SearchGrid DFS 4-directional recursion + backtrackingmedium
Also Important
9 more questions worth practicing.
- 19.Climbing StairsFibonacci recursion + Memoizationeasy
- 20.K-th Symbol in GrammarParent character binary flip recursionmedium
- 21.Swap Nodes in PairsSwap head & head.Next recursivelymedium
- 22.Decode StringParse nested multiplier strings recursivelymedium
- 23.Different Ways to Add ParenthesesSplit expression by operator Divide & Conquermedium
- 24.Unique PathsGrid DFS (down + right) + Memoizationmedium
- 25.N-QueensRow-by-row board placement backtrackinghard
- 26.Sudoku SolverGrid cell 1-9 trial & validation recursionhard
- 27.Tower of HanoiMove N-1 to temp, 1 to target, N-1 to targetmedium
How to Think
- Can problem become a smaller same problem?Recursion
- Tree problem?Recursion
- Need try all choices?Recursion + Backtracking
- Need divide problem into smaller parts?Recursion (Divide & Conquer)
- Same work repeats many times?Recursion + Memoization
Recursive Thinking Template & Go Example
3 Golden Questions for Every Recursive Function:
- What does my function mean? (e.g. maxDepth(node))
- What is the smallest / Base Case? (node == nil -> 0)
- How do I reduce the problem? (1 + max(left, right))
func maxDepth(root *TreeNode) int {
// 1. Base Case (stops recursion)
if root == nil {
return 0
}
// 2. Reduce Problem (subproblems for left & right children)
leftDepth := maxDepth(root.Left)
rightDepth := maxDepth(root.Right)
// 3. Return answer back upward
return 1 + max(leftDepth, rightDepth)
}👉 Calls go DOWN call stack → Answers return UPWARD
Two Essentials Every Recursion Needs
if n <= 1 { return 1 }Stops recursion. Without a base case, the function calls itself infinitely until stack overflow crash!
factorial(n) -> factorial(n-1)Each recursive call must move strictly closer toward the stopping base case.
Recursion vs Iteration
Recursion calls itself (using the call stack), while iteration uses explicit loops (for / while).
Use Recursion when problem structure is naturally recursive:
Call → Smaller Problem → Base Case → Return Answer Upward
Tree/DFS → Recursion
All choices → Recursion + Backtracking
Repeated → Memoization💡 Golden Rule: "Define what one recursive call should solve, make the problem smaller, and trust the next call to solve the rest."
Common Interview Mistakes
Forgetting base case condition leads directly to infinite recursion and stack overflow crashes!
Dereferencing node fields (node.Val) before checking node == nil causes null pointer panics.
Calling dfs(child) without saving or returning its result ignores critical subproblem answers.
Recursion uses implicit call stack space (O(depth)) even without allocating explicit arrays.
Interview Rules
- 1. Tree problem? → Think Recursion
- 2. DFS traversal? → Recursion fits naturally
- 3. Try every choice? → Recursion + Backtracking
- 4. Base case required first to specify stopping condition
- 5. Every call must reduce problem size toward base case
- 6. Call stack space =
O(recursion depth) - 7. Deep recursion risk → Watch out for stack overflow on massive inputs
- 8. Repeated subproblems? → Use Memoization cache
- 9. Multiple branching calls (e.g. fib(n-1) + fib(n-2)) → Watch out for exponential time
O(2^N)
Small Rules
- Rule 1: Always find and write the base case first.
- Rule 2: Each call must move strictly toward stopping (e.g. n-1).
- Rule 3: Recursion implicitly consumes O(depth) memory on call stack.
- Rule 4: Two branching calls without memoization cause O(2^N) exponential explosion.
- Rule 5: Always calculate the total number of function calls to determine time complexity.
Production Thinking
Nested Folder Traversal → Visit directory & recursively process nested subfolders
JSON / AST Parsing → Traverse arbitrarily nested JSON objects & abstract syntax trees
UI Component Trees → React Virtual DOM rendering & event bubbling up component tree
Package Dependency Resolution → Walk package dependency trees with cycle detection guard
Production Stack Overflow Safety → Prefer iterative loops for extremely deep structures (millions of items)
Remember This
Recursion → function calls itself
Must have → base case
Each call → smaller problem
Calls → go down
Answers → come back up
Tree / DFS → recursion
All choices → recursion + backtracking
Repeated work → memoization
Very deep calls → stack risk💡 Golden Rule: "Define what one recursive call should solve, make the problem smaller, and trust the next call to solve the rest."