Backtracking
Use when: generating all valid combinations, permutations, or subsets; constraint satisfaction.
Signal words: all combinations, all permutations, all subsets, generate, find all valid, N-Queens, Sudoku.
Core Idea
DFS + undo. At each step, make a choice, recurse, then undo the choice to explore other branches.
Template
def backtrack(start, current):
if is_complete(current):
result.append(current[:]) # snapshot, not reference
return
for choice in get_choices(start):
if is_valid(choice, current):
current.append(choice)
backtrack(next_start(choice), current)
current.pop() # undo
result = []
backtrack(0, [])Pruning
The difference between slow and fast backtracking is pruning - skipping branches early when you know they can’t lead to a valid answer.
Common Patterns
- Subsets: choose to include or exclude each element
- Permutations: pick from remaining elements (no index tracking needed if using used[] set)
- Combinations: pick from index forward to avoid duplicates
Deduplication with duplicates in input
Sort first, then skip choices[i] == choices[i-1] when i > start.