Explore all combinatorial possibilities through depth-first recursion, systematically making a choice, exploring its consequences, and pruning or undoing the choice (backtracking).
Core Invariant: DFS on a Decision Tree: at each node: 1) Check base case; 2) Iterate over choices; 3) Prune invalid choices early; 4) Make choice; 5) Recurse; 6) Undo choice (restore state).
Recognize it (Keywords & Signals)
Generate all permutations, combinations, or subsets
Find all valid configurations (N-Queens, Sudoku)
Word search in a 2D grid
Generate parentheses
Partition array into equal sum subsets
When NOT to use
Only the optimal value (count, min, max) is needed, not the actual paths/subsets (usually DP instead of backtracking!).
How to solve (Step-by-step)
1.Define `backtrack(start_idx, current_path)`.
2.Base case: if `current_path` meets length or target, add a deep copy `ans.append(list(current_path))` and return.
3.Loop through candidate elements from `start_idx` to `n`.
4.Pruning: skip if candidate exceeds remaining budget or is duplicate: `if i > start_idx and nums[i] == nums[i-1]: continue`.
5.Choose: `current_path.append(nums[i])`.
6.Recurse: `backtrack(i + 1, current_path)`.
7.Unchoose: `current_path.pop()`.
Watch for (Interview Traps)
Appending `path` instead of `path.copy()` or `list(path)` (results in empty arrays after unchoose pops)
Forgetting to sort before skipping duplicates (`nums[i] == nums[i-1]`)
Incorrect recursion index: `backtrack(start + 1)` instead of `backtrack(i + 1)` in recursive call
Combinations / Subsets with Pruning
def subsets_with_dup(nums: list[int]) -> list[list[int]]:
nums.sort() # Sorting is mandatory to group duplicates for pruning
result = []
def backtrack(start: int, path: list[int]) -> None:
# Every node in the decision tree is a valid subset
result.append(list(path)) # Important: copy current path!
for i in range(start, len(nums)):
# Prune duplicate branches at the same tree level
if i > start and nums[i] == nums[i - 1]:
continue
path.append(nums[i]) # Make choice
backtrack(i + 1, path) # Explore choice (i + 1 prevents reuse)
path.pop() # Undo choice (backtrack)
backtrack(0, [])
return result
Cost
O(2^n) subsets, O(n!) permutations · O(n) recursion call stack depth (Pruning invalid branches early is crucial for passing time limits.)
Canonical problems
#78 Subsets:Explore 2^n include/exclude decision tree
#46 Permutations:Explore all n! orderings using visited set
#39 Combination Sum:Allow reuse of same element with target reduction
#51 N-Queens:Prune attacks along cols, positive diagonals, negative diagonals
What is the Backtracking & Exhaustive Search pattern in coding interviews?
Combinations, permutations, and constraint satisfaction through pruned search trees It is categorized under Advanced & DP and features 115 curated interview problems across Easy (3), Medium (77), and Hard (35) difficulties.
Which tech companies frequently test Backtracking & Exhaustive Search?
How do I master the Backtracking & Exhaustive Search pattern?
Start by studying the algorithmic strategy and template code, then practice Easy and Medium problems before attempting Hard problems under timed conditions.