Backtracking 101
Advanced · 4 chapters · 9 min read · Explore every choice with one clean recursive template, and prune what cannot work.
Practise this in the app All guides
What backtracking is
Try, recurse, undo
Backtracking builds a solution one choice at a time. At each step it tries every valid option, recurses to make the next choice, and then undoes the option before trying the next one. Picture it as a depth-first walk over a tree of decisions: each path from the root to a leaf is one complete candidate. Whenever a partial path can no longer lead to a valid answer, you stop exploring it; this is called pruning, and it is what makes backtracking practical.
Signals in a problem statement
- "Return all" subsets, permutations, combinations, partitions, or arrangements.
- "Place N queens", "solve the Sudoku", "fill the board".
- "Does the word exist in the grid?" following adjacent cells without reuse.
- "Generate all valid parentheses", "all phone-keypad letter combinations".
- Constraints are small: n ≤ 10 to 20. Exponential time is expected and acceptable.
If the question asks only for a count or the best value and the constraints are large, dynamic programming is often the better tool; backtracking enumerates every option.
The three decisions
Before writing code, answer three questions:
- State: what describes a partial solution? (the current path, an index into the input, the remaining target)
- Choices: what can be added next from this state?
- Goal: when is the path complete and worth recording?
Then add pruning: which choices can be rejected immediately? For example, in combination sum, once the sorted candidates exceed the remaining target, every later candidate does too, so you can stop the loop.
Mental model
Think of exploring a maze with a ball of thread. You walk forward, and when you hit a dead end you wind the thread back to the last junction and take the next turn. The "undo" step is winding back the thread.
Core patterns with templates
The universal template
def backtrack(state, choices):
if is_goal(state):
record(state)
return
for c in choices(state):
if valid(state, c):
apply(state, c)
backtrack(state, choices)
undo(state, c)
1. Subsets (include or skip, by start index)
def subsets(nums):
out, path = [], []
def go(start):
out.append(path[:])
for i in range(start, len(nums)):
path.append(nums[i])
go(i + 1)
path.pop()
go(0)
return out
path[:] copies the list; appending path itself would record the same list object every time, which ends up empty.
2. Combination sum (reuse allowed, prune on sorted input)
def combination_sum(cands, target):
cands.sort()
out, path = [], []
def go(start, remain):
if remain == 0:
out.append(path[:])
return
for i in range(start, len(cands)):
if cands[i] > remain:
break
path.append(cands[i])
go(i, remain - cands[i])
path.pop()
go(0, target)
return out
Passing i (not i + 1) allows the same number again. Example: [2, 3, 6, 7], target 7 gives [2, 2, 3] and [7].
3. Grid search with temporary marking
def exist(board, word):
rows, cols = len(board), len(board[0])
def go(r, c, k):
if k == len(word):
return True
if not (0 <= r < rows and 0 <= c < cols) or board[r][c] != word[k]:
return False
board[r][c] = "#"
found = any(go(r + dr, c + dc, k + 1) for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)))
board[r][c] = word[k]
return found
return any(go(r, c, 0) for r in range(rows) for c in range(cols))
4. N-Queens with constraint sets
Place one queen per row. Track used columns and both diagonals (r - c and r + c) in sets so each check is O(1).
def n_queens(n):
cols, d1, d2, out, pos = set(), set(), set(), [], []
def go(r):
if r == n:
out.append(["." * c + "Q" + "." * (n - c - 1) for c in pos])
return
for c in range(n):
if c in cols or r - c in d1 or r + c in d2:
continue
cols.add(c); d1.add(r - c); d2.add(r + c); pos.append(c)
go(r + 1)
cols.remove(c); d1.remove(r - c); d2.remove(r + c); pos.pop()
go(0)
return outComplexity, mistakes and edge cases
Complexity
| Problem | Number of results | Typical time |
|---|---|---|
| Subsets | 2^n | O(n · 2^n) |
| Permutations | n! | O(n · n!) |
| Combinations of size k | C(n, k) | O(k · C(n, k)) |
| N-Queens | far fewer than n! after pruning | roughly O(n!) |
| Word search | O(rows · cols · 3^L) |
The extra factor of n (or k) comes from copying each result. Space is O(depth) for the recursion and the path, plus the output.
Common mistakes
- Not copying the path when recording it (
out.append(path)instead ofpath[:]). - Forgetting to undo. Every
appendneeds a matchingpop; every board mark needs a restore. A missing undo corrupts later branches silently. - Duplicate results when the input has repeated values. Sort first, then skip
nums[i]ifi > start and nums[i] == nums[i - 1]. - Wrong start index.
i + 1means each element at most once;imeans reuse allowed;0with ausedarray means permutations. - Checking the goal too late, after already going out of bounds, or recording a result before it is complete.
- No pruning. Without the early
breakin combination sum, the search explores many paths that can never succeed. - Recursion depth. Usually fine because n is small, but a word of 10⁴ characters on a grid could exceed Python's limit.
Edge cases
Empty input (subsets returns [[]]), target 0, candidates larger than the target, n = 1, n = 2 and n = 3 for N-Queens (no solution for 2 and 3), a word longer than the number of cells, and single-cell boards.
Estimating whether it will finish
Before coding, estimate the size of the search tree. For n = 20 subsets, 2^20 is about a million: fine. For 12 permutations, 12! is about 479 million: too slow in Python without strong pruning. Saying this estimate aloud shows the interviewer you understand the cost.
Variations and practise
How interviewers twist it
- Permutations with duplicates. Sort, keep a
usedarray, and skip a value if it equals the previous one and the previous one is not currently used. - Each number used once, with duplicates in the input (combination sum II). Sort, recurse with
i + 1, and skip equal neighbours at the same depth. - Palindrome partitioning. The choice at each step is where to cut next; only recurse when the piece is a palindrome. Precompute a palindrome table to speed up the check.
- Generate valid parentheses. Track open and close counts; add
(whileopen < n, and)whileclose < open. - Sudoku solver. Pick the empty cell with the fewest options first; this pruning makes a huge difference.
- Count instead of list. If only the number of solutions is needed, return counts from the recursion; with overlapping states, add memoisation and it becomes dynamic programming.
- Word search for many words. Build a trie of the words and walk it alongside the grid so you search all words at once.
How to explain it
Describe the state, the choices and the goal before coding: "The state is the current row; the choices are the columns not attacked; the goal is reaching row n." Then name your pruning rule.
Practise
The problems below cover subsets, combinations with reuse, searching a word in a grid, and N-Queens. Use the same template for all of them and notice that only the state, the choices and the goal change.
Practise
Easy
- 3048. Binary Watch
- 3049. Sum of All Subset XOR Totals
- 3055. Signal Strings Without Back-to-Back Pulses
- 3059. Every Capitalization of a Code
- 3061. Arrange the Name Tags
- 3062. Pick a Committee
- 3063. Dice Rolls That Reach a Total
- 3064. Trail Markers From Root to Leaf
- 3065. Climbing-Digit Numbers
- 3066. Follow the Letter Rules
- 3067. Tile Rows With No Matching Neighbors
- 3068. Unrepeating PIN Codes
- 3069. Stepping-Stone Sequences
- 3070. Fill the Wildcards
- 3071. Every Reachable Total
- 3072. Fair Split of Candy Bags
- 3073. Mirror Picks From a Short Word
- 3074. Non-Decreasing Letter Codes
- 3075. Digits Along the Branches
- 3076. Plus or Minus to Hit the Mark
- 3077. Nobody in Their Own Seat
- 3078. Nine Numbered Tiles
- 3079. Selections Under a Product Cap
- 3080. Domino Word Builder
- 3081. Rising Branches
- 3082. Odd-Even Alternating Lineups
- 3083. Numbers With a Given Digit Sum
- 3084. Mirror Words From a Letter Bag
- 3085. Gift Swap Pairings
- 3086. Plus Signs in a Digit String
- 3087. Latest Clock From Four Digits
- 3088. Strings at an Exact Flip Distance
- 3089. Trim k Letters
- 3148. Smudged Word Lookup
Medium
- 3050. Subsets
- 3051. Combination Sum
- 3052. Word Search
- 3056. Well-Nested Brackets
- 3057. Old Phone Spellings
- 3058. Unique Arrangements of Repeated Beads
- 3090. Distinct Bags From a Duplicate Pile
- 3091. Exact Change From a Coin Jar
- 3092. Mirror-Piece Splits
- 3093. Dotted Address Recovery
- 3094. Branches Totaling a Target
- 3095. Divisible Seating
- 3096. Distinct Stamp Sequences
- 3097. Longest Unique-Letter Chain
- 3098. Mine-Cart Treasure Run
- 3099. Steady-Step Numbers
- 3100. Ascending Splits of a Digit String
- 3101. Most Distinct Pieces
- 3102. Shuffle-to-Mirror Branches
- 3103. Equal Shares for k Friends
- 3104. Balance the Workload
- 3105. Peaceful Kings
- 3106. Running-Sum Digit Strings
- 3107. Shorthand Variants of a Word
- 3108. Product Breakdowns
- 3109. Pattern-to-Phrase Mapping
- 3110. All Bracketings of an Expression
- 3111. Pronounceable Codes
- 3112. Rising Subsequences
- 3113. The k-th Ordering
- 3114. Dictionary-Order Counting
- 3115. Square-Linked Chains
- 3117. Even Teams, Closest Strength
- 3118. No Twin Neighbors
- 3119. Budget-Window Baskets
- 3120. Mentor Matching Score
- 3121. Every Route Through the Pipeline
- 3122. Two Disjoint Mirror Picks
- 3123. Distance-Paired Sequence
- 3124. Rise-and-Fall Code
- 3125. Spread the Pebbles
- 3126. Pick Columns to Cover Rows
- 3127. Full-Power Subsets
- 3128. Gap-Free Teams
- 3129. Split Into Powers-of-Five Codes
- 3130. Self-Summing Squares
- 3131. Number Pool Duel
- 3132. Exact-Length Walks
- 3133. Longest Scenic Route
- 3134. Visible-From-the-Left Lineups
- 3135. Use Every Ticket
- 3136. Domino Coverings of a Cracked Floor
- 3137. Complete the Magic Square
- 3138. Selections With a Given Average
- 3139. Distinct-Letter Trek
- 3140. All Ways to Group Guests
- 3141. Quiet Guests
- 3142. Grid From Row and Column Counts
- 3143. Code-Breaker Consistency
- 3144. Primes From Scattered Digit Cards
- 3145. Circle Picks Without Neighbours
- 3146. One Dish per Course
- 3147. Switch Settings That Satisfy Every Rule
- 3149. Lights-Out Grid
- 3150. Repair the Smudged Sum
- 3151. Stack the Bracket Fragments
- 3152. Pyramid Top Total
- 3153. Distinct Bead Loops
- 3154. Feuding Neighbours Seating
Hard
- 3053. N-Queens
- 3054. Sudoku Solver
- 3060. Find Every Hidden Word
- 3116. Fewest Swaps Between Anagrams
- 3155. Insert Operators to Hit the Target
- 3156. Fewest Bracket Removals
- 3157. Knight's Grand Tour
- 3158. Every Open Cell Exactly Once
- 3159. Highest-Scoring Word Set
- 3160. Word Square Builder
- 3161. Fill the Crossword Grid
- 3162. Letter Arithmetic
- 3163. Closest Subset Sum
- 3164. Fewest Square Tiles
- 3165. Least Clashing Groups
- 3166. Settle the Tab
- 3167. Sticker Ransom
- 3168. Dorm Swap Requests
- 3169. Make Twenty-Four
- 3170. Smallest Skill Squad
- 3171. Pack the Shapes
- 3172. Picture Puzzle Grid
- 3173. Fewest Truck Loads
- 3174. Fewest Watchtowers
- 3175. Rebuild Numbers From Pair Sums
- 3176. Board Duel Verdict
- 3177. Same Network, Different Labels
- 3178. Fewest Paint Colours
- 3179. Longest Word-Card Chain
- 3180. Shortest Merged Message
- 3181. Shortest Delivery Loop
- 3182. Peg Jump Puzzle
- 3183. Number Snake Puzzle
- 3184. Fewest Straight Lines Through Every Point
- 3185. Sum-Clue Grid Puzzle
- 3186. Possible Final Standings