Backtracking
Choose, explore, un-choose — walk every branch of the decision tree.
- Brute force
- Same exponential search, but rebuilding lists each call costs extra
- With the pattern
- O(2ⁿ · n) subsets, O(n! · n) permutations — proportional to output
- Extra space
- O(n) — recursion depth + current path
In plain English
“Packing a picnic basket by trying combinations: you put an apple in, see what else you could add, then take the apple back out and try without it. Because you always undo your last move before trying the next option, the basket is always in the right state for whatever you try next.”
Why it's fast
Some problems genuinely need every answer (all subsets, all permutations), so exponential output is unavoidable. Backtracking makes it cheap per answer by reusing one mutable path: append, recurse, pop. Pruning (stop when the sum exceeds target, skip duplicate values) cuts whole subtrees before you waste time inside them.
Spot it when the problem says…
- return all possible subsets / combinations / permutations
- generate all valid …
- each number may be used once / unlimited times
- place n queens / solve sudoku
- partition a string into …
- word search in a grid
Visualize
Subsets — walk the decision tree
Return every subset of nums. Each node of the tree is one subset.
path
result (1)
Record [] — every node in this tree is a valid subset.
1def subsets(nums):2 result, path = [], []3 def backtrack(start):4 result.append(path[:]) # every node is an answer5 for i in range(start, len(nums)):6 path.append(nums[i]) # choose7 backtrack(i + 1) # explore8 path.pop() # un-choose9 backtrack(0)10 return resultvariables
- start
- 0
How to apply it
- 01Define the state: a
pathlist plus astartindex (combinations) orusedset (permutations). - 02Base case: if the path is a complete answer, record a copy (
path[:]). - 03Loop over the next choices: choose (append), explore (recurse), un-choose (pop).
- 04Add pruning: break when a sorted candidate already overshoots; skip equal neighbours to avoid duplicates.
Variations you'll meet
Subsets (take / skip tree)
The visualizer's example: every node of the decision tree is an answer.
def subsets(nums: list[int]) -> list[list[int]]: res, path = [], [] def backtrack(start: int) -> None: res.append(path[:]) # every node is a subset for i in range(start, len(nums)): path.append(nums[i]) # choose backtrack(i + 1) # explore path.pop() # un-choose backtrack(0) return resPermutations (used set)
Order matters, so every position can take any unused element; no start index.
def permute(nums: list[int]) -> list[list[int]]: res, path, used = [], [], [False] * len(nums) def backtrack() -> None: if len(path) == len(nums): res.append(path[:]) return for i, x in enumerate(nums): if used[i]: continue used[i] = True path.append(x) backtrack() path.pop() used[i] = False backtrack() return resCombination Sum (reuse allowed + pruning)
Recurse with i (not i + 1) so a number can repeat; sort and break once a candidate exceeds the remainder.
def combination_sum(candidates: list[int], target: int) -> list[list[int]]: candidates.sort() res, path = [], [] def backtrack(start: int, remain: int) -> None: if remain == 0: res.append(path[:]) return for i in range(start, len(candidates)): c = candidates[i] if c > remain: break # sorted: rest are too big path.append(c) backtrack(i, remain - c) # i, not i+1: reuse allowed path.pop() backtrack(0, target) return resDuplicates in input
Sort, then if i > start and nums[i] == nums[i-1]: continue (Subsets II, Combination Sum II).
Common mistakes
- Appending
pathinstead ofpath[:]— every saved answer ends up as the same (empty) list. - Forgetting to pop (un-choose), so the path keeps growing across branches.
- Using
i + 1vsivsstartwrongly — mixes up reuse, combinations and permutations. - Dedup check
i > 0instead ofi > start, which wrongly skips valid answers. - In grid word search, not restoring the cell after marking it visited.
Practice ladder
Easy → hard. Tick them off as you go.
Think you've got it?
Let the AI interviewer throw a Backtracking problem at you and grade how you explain it.