Week 08 — Backtracking: The Decision-Tree Discipline
Month 02, Week 04 (overall week 08) · 5 problems · 3 mediums + 1 medium-hard + 1 hard Theme: Search trees with explicit choose / recurse / un-choose. Pruning. Lexicographic vs free order. Symmetry breaking.
Why this week
Backtracking is the technique most candidates fake. They produce code that “works on the example” but breaks on duplicates, fails to deduplicate, mutates the wrong state, or — most commonly — forgets to un-choose. By the end of this week you will:
- Have a single mental template you write reflexively: choose → recurse → un-choose.
- Distinguish permutations (order matters, all elements used,
used[]tracker) vs combinations (size-k subset, monotonically non-decreasing index) vs subsets (powerset, include/exclude at each index). - Prune at the FIRST opportunity instead of at the leaf — the difference between TLE and AC.
- Handle the duplicate-input variant (sort + skip equal siblings) and the lex-order vs free-order distinction.
- Solve a 2D grid backtracking problem (Word Search) with in-place visited-marking.
- Build N-Queens — the canonical “symmetry-breaking + column/diagonal sets” problem — in under 20 minutes.
Problems
| # | Problem | Difficulty | LC | Pattern signature |
|---|---|---|---|---|
| p36 | Permutations | Medium | 46 | used[] tracker; n! leaves |
| p37 | Combinations | Medium | 77 | start-index + k constraint; C(n,k) leaves |
| p38 | Subsets | Medium | 78 | include/exclude OR iterative powerset; 2^n leaves |
| p39 | Word Search | Medium-Hard | 79 | grid backtracking + in-place visited |
| p40 | N-Queens | Hard | 51 | column + diag + anti-diag sets; row-by-row |
Daily schedule (5 days)
| Day | Problem | Stop at |
|---|---|---|
| Mon | p36 Permutations | clean template, both used[] and swap-in-place |
| Tue | p37 Combinations | start-index + early termination |
| Wed | p38 Subsets | both DFS and iterative |
| Thu | p39 Word Search | in-place visited, prune on first char mismatch |
| Fri | p40 N-Queens | three sets (col, diag, anti-diag) — O(n!) bounded by pruning |
Readiness gate (end of week)
You can move to Week 9 when you can:
- Write the universal backtracking template (choose / recurse / un-choose) in under 60 seconds.
- Solve any “all permutations / all combinations / all subsets” variant in under 15 min.
-
Explain WHY
used[]is needed for permutations but astartindex suffices for combinations and subsets. -
Handle the with-duplicates variant (
sort()+if i > start and a[i] == a[i-1]: continue) without looking it up. - Word Search: explain why in-place visited-marking saves O(n·m·L) memory.
-
N-Queens: place the THREE attacker sets (col, diag =
r + c, anti-diag =r - c) from memory. - Articulate the difference between “exponential time” (unavoidable for enumeration) vs “exponential WORK PER NODE” (pruning attacks the constant).
Anti-patterns to crush this week
- Building strings via
s + chinside recursion (O(L) copy per call) — use alistand.append()/.pop(). - Forgetting
.pop()after.append()— your “current path” leaks into siblings. - Passing
path[:]to recurse — works but wastes O(L) per call; the un-choose pattern is cleaner. - Returning a
setof tuples to deduplicate at the end — should have pruned at the source via sort+skip. - Word Search marking visited with a separate
set— use in-place sentinel ('#') and restore. - N-Queens validating a board column-by-column on each placement — use sets (O(1) lookup).
- Re-counting
len(path) == kin the loop instead of at function entry.
Sources
- Sedgewick, Algorithms, Ch 2 (Backtracking).
- CLRS, Ch 35 (Approximation), Ch 34 (NP) — for the “why exponential is fundamental” perspective.
- Skiena, Algorithm Design Manual, Ch 9 (Combinatorial Search).