DSA Tutorial
🔍

Recursion Practice Problems

How to Use This Problem List

Recursion problems fall into a small number of structural patterns. Recognising the pattern within two minutes of reading is the key skill — not the implementation itself.

The two most important questions for any recursion problem:

  1. What is the smallest version of this problem? (→ base case)
  2. How does solving a smaller version help solve the full problem? (→ recursive case)

If you can answer both clearly before writing code, the implementation follows mechanically.

Pattern 1: Linear Recursion — Reduce and Return

The simplest pattern. One recursive call per level, problem shrinks by a fixed amount (usually 1 or 1/2), result is computed by combining the current level's data with the sub-call's result.

ProblemDifficultyRecognition ClueKey Insight
FactorialEasy"n! = n × (n-1)!"f(n) = n × f(n-1), base f(0) = 1
Sum of 1 to NEasy"sum first n integers recursively"f(n) = n + f(n-1), base f(0) = 0
Power of TwoEasy"is n a power of 2 recursively"Divide by 2 each call; base: n==1 true, n==0 false
Reverse a StringEasy"reverse string without built-in"f(s) = f(s[1:]) + s[0], base empty string
Count Occurrences in ArrayEasy"count target in array recursively"f(arr, i) = (arr[i]==target) + f(arr, i+1)
Sum of DigitsEasy"sum digits of integer recursively"f(n) = (n%10) + f(n//10), base n < 10
Check PalindromeEasy"is string a palindrome recursively"Match outer chars, recurse on inner substring
GCD (Euclidean)Easy"greatest common divisor recursively"gcd(a,b) = gcd(b, a%b), base b==0 return a
Count Zeros in IntegerEasy"count zeros in digits of n"f(n) = (n%10==0) + f(n//10), base n < 10
First Index of ElementEasy"first index where arr[i] == target"Return i if match, else f(arr, target, i+1)

Complexity target: O(n) time, O(n) space (call stack).

Recognition signal: "recursively compute X for n", "check property of n", "transform string/number one step at a time". A single chain of calls where each level does O(1) work.

Pattern 2: Divide and Conquer

Split the problem into two or more smaller subproblems of roughly equal size, solve each recursively, then merge the results. The recursion tree is a balanced binary tree.

ProblemDifficultyRecognition ClueKey Insight
Binary SearchEasy"find target in sorted array O(log n)"Compare mid, recurse into one half only
Merge SortMedium"sort array using divide and conquer"Split in half, sort each, merge O(n)
Maximum Subarray (divide conquer)Hard"max subarray using divide and conquer"Max is in left, right, or crosses mid
Count InversionsMedium"count pairs where i<j but arr[i]>arr[j]"Merge sort variant: count right-picks during merge
Median of ArrayHard"find median using divide and conquer"QuickSelect: partition, recurse into one half
Closest Pair of PointsHard"minimum distance between any two points"Split by x-coord, merge considers strip near divide line
Exponentiation by SquaringMedium"x^n in O(log n)"pow(x,n) = pow(x,n/2)² if n even, else x × pow(x,n-1)²
Find Maximum in ArrayEasy"maximum element recursively"max(arr) = max(arr[0], max(arr[1:]))
Majority ElementEasy"element appearing > n/2 times"Divide: if same majority in both halves, that is the answer

Complexity target: O(n log n) for sorting, O(log n) for search, O(n log n) for most divide-and-conquer.

Recognition signal: "O(log n)", "divide in half", "sort and merge", "closest/farthest pair". The problem naturally halves at each level.

Pattern 3: Tree Recursion

Problems defined on tree data structures where the answer for a node depends on the answers for its children. Nearly every tree problem is recursive by nature.

ProblemDifficultyRecognition ClueKey Insight
Maximum Depth of Binary TreeEasy"height of tree"1 + max(depth(left), depth(right)), base null→0
Diameter of Binary TreeMedium"longest path between any two nodes"Max of: left_depth + right_depth at each node
Balanced Binary TreeEasy"is tree height-balanced"Height diff ≤ 1 at every node; use -1 sentinel for unbalanced
Same TreeEasy"are two trees identical"Nodes must match AND left subtrees AND right subtrees
Symmetric TreeEasy"is tree a mirror image of itself"isMirror(left, right): values match AND cross-subtrees match
Path SumEasy"does any root-to-leaf path sum to target"Subtract node value each level; base: leaf AND remaining==0
Path Sum II (all paths)Medium"find all root-to-leaf paths summing to target"Backtrack: add node, recurse, remove on return
Lowest Common AncestorMedium"deepest node that is ancestor of both p and q"Both in left? recurse left. Both in right? recurse right. Else current node
Invert Binary TreeEasy"flip tree horizontally"Swap left and right, then recurse into each
Flatten Tree to Linked ListMedium"flatten tree into right-skewed list in-place"Post-order: flatten left, flatten right, stitch together
Count Good NodesMedium"node is good if no larger value on path from root"Pass max-so-far down; count if node.val ≥ max
Sum Root to Leaf NumbersMedium"integers formed by root-to-leaf paths"Pass accumulated number down; at leaf add to total

Complexity target: O(n) time (visit every node once), O(h) space where h = tree height.

Recognition signal: "binary tree", "height/depth/balance", "path sum", "compare two trees", "ancestor". Any problem about a tree node's relationship to its subtrees.

Pattern 4: Backtracking — Generate All Solutions

Explore all possible arrangements, subsets, or paths by making a choice, recursing, and undoing the choice. The recursion tree has one branch per choice at each decision point.

ProblemDifficultyRecognition ClueKey Insight
SubsetsMedium"all subsets of a set"At each index: include or exclude; 2^n leaf paths
PermutationsMedium"all permutations of a list"Swap current with each subsequent; recurse; swap back
CombinationsMedium"all combinations of k elements from n"Include current, recurse for k-1; skip current, recurse
Letter Combinations of Phone NumberMedium"all words from digit mapping"For each digit, branch into its letters
Word SearchMedium"does word exist in 2D grid"DFS: mark visited, recurse in 4 directions, unmark
N-QueensHard"place n queens so none attack each other"Place queen in each column of current row; check conflicts
Sudoku SolverHard"fill sudoku grid"Try digits 1-9 in each empty cell; backtrack if invalid
Generate ParenthesesMedium"all valid parenthesis combinations for n pairs"Add '(' if open_count < n; add ')' if close < open
Palindrome PartitioningMedium"all ways to partition string into palindromes"Try every prefix; if palindrome, recurse on suffix
Combination SumMedium"all combinations summing to target (reuse allowed)"Include current, recurse with same index; skip, advance index
Combination Sum IIMedium"all combinations summing to target (no reuse)"Sort; skip duplicates at same recursion level
Restore IP AddressesMedium"all valid IP addresses from digit string"Branch on segment lengths 1,2,3; validate each segment

Complexity target: O(2ⁿ) for subsets, O(n!) for permutations, problem-specific for others.

Recognition signal: "all possible", "generate all", "find all combinations/permutations/arrangements", "does any path exist". The word "all" or the need to explore every option is the trigger.

Pattern 5: Structural Recursion — Nested Data

The problem's data is recursively structured (nested lists, linked lists, expression trees). The base case is the atom of the structure.

ProblemDifficultyRecognition ClueKey Insight
Flatten Nested ListMedium"convert nested list to flat list"Base: not a list (atom) → return [atom]; else recurse into each element
Evaluate Reverse Polish NotationMedium"evaluate expression in postfix"Stack-based, but recursion on expression tree is clean
Decode StringMedium"expand k[encoded_string] recursively"Base: no brackets; Recursive: decode inner string, repeat k times
Nested List Weight SumMedium"each integer multiplied by its nesting depth"Pass depth as parameter; base: integer → depth × val
Parse Nested ListHard"parse '[1,[4,[6]]]' into nested structure"Recursive descent parser — base: digit; recursive: '[', recurse, ']'
Reverse Linked ListEasy"reverse singly linked list recursively"f(head) = f(head.next) then set head.next.next = head, head.next = null
Merge Two Sorted ListsEasy"merge two sorted linked lists recursively"Base: either null → return other; pick smaller head, recurse on rest
Copy List with Random PointerHard"deep copy linked list with random pointers"HashMap of original → copy; recurse on next and random

Complexity target: O(n) where n is the total number of elements across all nesting levels.

Recognition signal: "nested", "linked list", "parse", "expand", "decode", "deep copy". The structure mirrors the recursion — the recursive call processes a structurally smaller version.

Pattern 6: Mathematical and Number Recursion

Problems where the recursion is defined by mathematical relationships — number theory, sequences, geometric progressions.

ProblemDifficultyRecognition ClueKey Insight
Fibonacci NumberEasy"nth Fibonacci number"f(n) = f(n-1) + f(n-2); use memoisation for O(n)
Climbing StairsEasy"ways to climb n stairs taking 1 or 2 steps"f(n) = f(n-1) + f(n-2) — identical to Fibonacci
Jump Game (recursive)Medium"can you reach the last index"f(i) = OR over reachable j > i: f(j)
Tower of HanoiMedium"move n disks from A to C using B"Move n-1 from A→B, move disk n from A→C, move n-1 from B→C
K-th Symbol in GrammarMedium"kth symbol in nth row of grammar pattern"Parent at position ⌈k/2⌉ in row n-1; if parent=0: child=k%2; if parent=1: child=1-k%2
Gray CodeMedium"binary reflected Gray code sequence"G(n) = 0-prefixed G(n-1) + 1-prefixed reversed G(n-1)
Integer to English WordsHard"convert integer to English words recursively"Recurse on chunks of 3 digits with appropriate suffix (thousand, million)
Perfect SquaresMedium"minimum number of perfect squares summing to n"f(n) = 1 + min over squares s≤n: f(n-s); use memoisation

Complexity target: O(n) with memoisation for sequence problems, O(2ⁿ) without.

Recognition signal: "nth term of sequence", "number of ways to", "how many", "convert number". A mathematical recurrence relationship is explicit or implicit in the problem statement.

Recommended Study Order

Week 1 — Linear and Divide and Conquer
  Pattern 1 (Linear): Reverse String, Sum Digits, Check Palindrome
  Pattern 2 (D&C):    Binary Search, Merge Sort, Exponentiation

Week 2 — Tree Recursion
  Pattern 3 (Tree):   Max Depth, Same Tree, Path Sum, Invert Tree
  Pattern 3 (Hard):   Diameter, Balanced, Lowest Common Ancestor

Week 3 — Backtracking
  Pattern 4 (Easy):   Subsets, Combinations, Letter Combinations
  Pattern 4 (Medium): Permutations, Generate Parentheses, Combination Sum

Week 4 — Advanced Patterns
  Pattern 5 (Structural): Merge Two Lists, Flatten Nested, Decode String
  Pattern 6 (Math):       Fibonacci (memoised), Tower of Hanoi, Climbing Stairs
  Pattern 4 (Hard):       N-Queens, Sudoku Solver, Word Search

Problem-Solving Checklist for Recursion Problems

Before writing code, answer these questions:

1. IDENTIFY THE BASE CASE
   □ What is the smallest input where the answer is known directly?
   □ Is this base case reachable from every valid input?
   □ Are all boundary cases handled? (empty array, null, n=0, n=1)

2. IDENTIFY THE RECURSIVE CASE
   □ What smaller version of the problem does this call?
   □ Is the argument strictly closer to the base case?
   □ How is the sub-call's result combined with the current level?

3. DETERMINE THE PATTERN
   □ Single chain → linear recursion
   □ Split in half + merge → divide and conquer
   □ Tree node + children → tree recursion
   □ Build and undo choices → backtracking
   □ Nested structure → structural recursion

4. ESTIMATE COMPLEXITY
   □ How many recursive calls per node?
   □ How deep is the recursion tree?
   □ How much work per node (excluding sub-calls)?
   □ Total = nodes × work-per-node  OR  levels × work-per-level

5. CHECK FOR OPTIMISATION
   □ Are sub-problems repeated? → memoisation (top-down DP)
   □ Is the recursive call in tail position? → iterative loop
   □ Is recursion depth > ~1000 (Python) or ~10000 (Java)? → iterative with explicit stack

6. EDGE CASES
   □ Empty input (array, string, tree null)
   □ Single element
   □ All elements identical
   □ Maximum depth inputs (large n)

Pattern Recognition Quick Reference

Signal in ProblemPatternStructure
"recursively compute", "find nth"Linear recursionf(n) = combine(n, f(n-1))
"sort", "find in sorted", "O(log n)"Divide and conquerf(n) = merge(f(left), f(right))
"binary tree", "height/depth/path"Tree recursionf(node) = combine(node, f(left), f(right))
"all subsets/permutations/paths"Backtrackingfor choice: pick, f(smaller), unpick
"nested list/structure", "parse"StructuralBase = atom; recursive = container
"nth Fibonacci", "number of ways"Math recurrencef(n) = f(n-1) + f(n-2) with memoisation
"linked list reverse/merge"Linear structureBase = null; recursive = head + f(rest)
"word search", "grid path"2D backtrackingMark visited, 4-direction DFS, unmark

Difficulty Progression Reference

StageCharacteristicsRepresentative Problems
FoundationSingle base case, one recursive callFactorial, Reverse String, Max Depth Tree
Early IntermediateTwo recursive calls, tree structureFibonacci (memoised), Same Tree, Path Sum
IntermediateBacktracking, divide and conquerSubsets, Merge Sort, Generate Parentheses
Late IntermediateMulti-level backtracking, structuralCombination Sum, Palindrome Partition, Decode String
AdvancedHard backtracking, complex tree, classic hardN-Queens, Sudoku, Closest Pair, Word Search

Common Interview Topics by Company Focus

Product-based companies (FAANG-tier):

  • Subsets, Permutations, Combinations — backtracking fundamentals
  • Binary Tree problems (max depth, diameter, LCA) — tree recursion
  • Merge Sort / QuickSelect — divide and conquer
  • Word Search — 2D backtracking
  • Generate Parentheses — constrained backtracking

Service-based and on-campus:

  • Fibonacci (memoised), Tower of Hanoi — math recursion
  • Reverse Linked List, Merge Two Sorted Lists — structural recursion
  • Binary Search recursive — divide and conquer
  • Factorial, Palindrome Check — linear recursion

Startup and mid-size tech:

  • N-Queens, Sudoku Solver — constraint satisfaction backtracking
  • Decode String, Flatten Nested List — structural recursion
  • Climbing Stairs, Jump Game — math recurrence with memoisation
  • Invert / Flatten Binary Tree — tree recursion

Progress Tracking

After solving each problem, record:

  1. Pattern — which of the 6 patterns does this belong to?
  2. Base case(s) — what were they and were any non-obvious?
  3. Recursive case — how did it make progress toward the base?
  4. Tree shape — linear, branching, balanced, unbalanced?
  5. Complexity — what is O(time) and O(space)? How was it derived from the tree?
  6. Optimisation — did repeated subproblems suggest memoisation or iteration?

The decisive signal that pattern recognition is working: when you see "generate all valid parentheses" and immediately think "backtracking — two choices per position (open or close), pruned by open_count ≤ n and close_count ≤ open_count" before reading the constraints.

Suggested Quiz

A problem asks to 'generate all combinations' or 'find all subsets'. Which recursion pattern applies?

1/6
Recursion Practice Problems