Recursion & Backtracking Master Recap: Interview Cheatsheet

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Recursion & Backtracking Master Recap

Universal Template

def backtrack(state, choices):
    # Base case
    if is_complete(state):
        record_solution(state)
        return

    # Pruning
    if should_prune(state): return

    # Explore choices
    for choice in get_choices(choices):
        if is_valid(state, choice):
            make_choice(state, choice)     # CHOOSE
            backtrack(state, choices)      # EXPLORE
            undo_choice(state, choice)     # UNCHOOSE

Pattern Recognition Cheat Sheet

CuePatternTemplate
"generate all..."Subsets/Permsbt(start, current)
"find all valid..."Constraint satisfactionbt(row/idx, state)
"partition into..."Splittingbt(start, parts)
"place N pieces..."N-Queens stylebt(row, conflict_sets)
"fill a grid..."Sudoku stylebt(cell_idx, constraints)
"count arrangements"Bitmask DP or btdp[mask]
"min removals..."BFS level-by-levelBFS + validity check

Duplicate Handling Rules

SituationRule
Subsets with dupsSort + if i > start and nums[i] == nums[i-1]: continue
Permutations with dupsSort + if i > 0 and nums[i] == nums[i-1] and not used[i-1]: continue
Combination Sum (no dups)Start next from i (reuse) or i+1 (no reuse)
Buckets/groupsTrack seen set for bucket values at same level

Optimization Checklist

Before coding, ask:

  1. Can I sort to enable early termination?
  2. Can I precompute valid choices? (N-Queens sets, palindrome table)
  3. Is there a DP that replaces backtracking? (subset sum, coin change)
  4. Can bitmask DP compress state? (arrangements, TSP)
  5. Should I prune by remaining capacity/length?

Template Library

# Subsets
def subsets(nums):
    res = []
    def bt(i, cur):
        res.append(cur[:])
        for j in range(i, len(nums)):
            cur.append(nums[j]); bt(j+1, cur); cur.pop()
    bt(0, [])
    return res

# Permutations
def permute(nums):
    res, used = [], [False]*len(nums)
    def bt(cur):
        if len(cur)==len(nums): res.append(cur[:]); return
        for i,n in enumerate(nums):
            if used[i]: continue
            used[i]=True; cur.append(n); bt(cur); cur.pop(); used[i]=False
    bt([]); return res

# Combination Sum
def combinationSum(cands, target):
    cands.sort(); res = []
    def bt(i, cur, rem):
        if rem==0: res.append(cur[:]); return
        for j in range(i, len(cands)):
            if cands[j]>rem: break
            cur.append(cands[j]); bt(j, cur, rem-cands[j]); cur.pop()
    bt(0, [], target); return res

# N-Queens
def nQueens(n):
    res, cols, d1, d2 = [], set(), set(), set()
    board = [['.']*n for _ in range(n)]
    def bt(r):
        if r==n: res.append([''.join(row) for row in board]); return
        for c in range(n):
            if c in cols or r-c in d1 or r+c in d2: continue
            board[r][c]='Q'; cols.add(c); d1.add(r-c); d2.add(r+c)
            bt(r+1)
            board[r][c]='.'; cols.discard(c); d1.discard(r-c); d2.discard(r+c)
    bt(0); return res

Top 30 Backtracking LeetCode Problems

#ProblemPattern
17Letter CombinationsRecursive tree
22Generate ParenthesesCount tracking
37Sudoku SolverCell-by-cell constraint
39Combination SumReuse + sort + prune
40Combination Sum IINo reuse + dup skip
46PermutationsUsed array
47Permutations IIUsed + dup skip
51N-QueensRow + set constraints
52N-Queens IICount only, bitmask
77CombinationsnCr, pruning
78SubsetsInclude/exclude
79Word SearchGrid DFS + unvisit
90Subsets IISort + dup skip
93Restore IP AddressesSegment validation
131Palindrome PartitioningPrecompute + bt
140Word Break IIMemo + bt
212Word Search IITrie + grid DFS
216Combination Sum IIIk-choose from 1-9
282Expression Add OperatorsOperator insertion
301Remove Invalid ParenthesesBFS min + DFS all
306Additive NumberPartition into additive
320Generalized AbbreviationInclude/exclude chars
351Android Unlock PatternsGrid DFS with skip
401Binary WatchPopcount combinations
416Partition Equal SubsetDP (not bt)
425Word SquaresTrie-guided bt
473Matchsticks to SquareK-bucket partition
526Beautiful ArrangementPosition-number validity
698Partition K Equal SubsetsBucket dedup
784Letter Case PermutationToggle case tree

Complexity Quick Reference

ProblemTimeNote
Subsets n elementsO(2^n * n)Copy cost
Permutations nO(n! * n)Copy cost
Combinations C(n,k)O(C(n,k) * k)
N-Queens n×nO(n!)With pruning
SudokuO(9^81) worstFast with constraints
Word Search L on m×nO(mn4^L)
Combination Sum target TO(T^(T/min))With pruning

Common Mistakes

  1. Forgetting to copy current state when recording solution
  2. Not restoring state after recursive call (missing undo)
  3. Wrong start index: reuse = bt(i,...), no-reuse = bt(i+1,...)
  4. Duplicate handling: must sort first, then check nums[i]==nums[i-1]
  5. Using list in set: use tuple(current) to add to set
  6. Off-by-one in pruning: check boundary conditions carefully

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro