DSA Notes
Master backtracking from the ground up — what backtracking is, how it differs from brute force, the universal backtracking template, state space tree visualization, pruning strategies that make backtracking efficient, and when to apply backtracking versus dynamic programming.
What Is Backtracking?
Backtracking is an algorithmic technique that considers searching every possible combination in order to solve a computational problem. It incrementally builds candidates for a solution and abandons (backtracks from) each partial candidate as soon as it determines that this candidate cannot lead to a valid complete solution.
The word backtrack literally means to go back the way you came — reversing a decision that turned out to be wrong and trying a different path.
The central idea: At each decision point, make one choice, proceed forward, and if you reach a dead end, undo that choice and try the next option. This "try and undo" cycle is what separates backtracking from simple recursion.
The State Space Tree
Every backtracking problem can be visualized as a state space tree — a tree where:
- The root represents the initial empty state
- Each edge represents one decision/choice
- Each node represents a partial solution (state)
- Leaf nodes represent complete solutions (or dead ends)
The Universal Backtracking Template
Every backtracking solution follows this exact pattern:
The three key actions are always:
- Choose — Make a decision, modify the state
- Explore — Recurse to explore the consequences
- Undo — Reverse the decision, restore previous state
First Complete Example — Generate All Permutations
Decision tree for [1,2,3]:
| Start | [] |
| Choose 1 | [1] |
| Choose 2 | [1,2] |
| Choose 3: [1,2,3] | COMPLETE ✓ |
| Choose 3 | [1,3] |
| Choose 2: [1,3,2] | COMPLETE ✓ |
| Choose 2 | [2] |
| Choose 1 | [2,1] |
| Choose 3: [2,1,3] | COMPLETE ✓ |
Second Example — Generate All Subsets
Pruning — The Heart of Efficiency
Without pruning, backtracking degenerates to exhaustive brute force. Pruning eliminates branches of the state space tree that cannot lead to valid solutions.
Example — Combination Sum with Pruning
Without the break (no pruning): Explores all 4^(target/min) combinations With the break (pruning): Eliminates all branches where sum would exceed target
Backtracking vs Dynamic Programming
Both solve optimization and enumeration problems, but they're suited for different scenarios:
| Aspect | Backtracking | Dynamic Programming |
|---|---|---|
| Goal | Find all solutions / any valid solution | Find optimal solution |
| Subproblems | Non-overlapping | Overlapping |
| Memory | O(depth) stack space | O(states) table |
| When to use | Constraint satisfaction, enumeration | Optimization with optimal substructure |
| Examples | N-Queens, Sudoku, permutations | Fibonacci, knapsack, LCS |
Rule of thumb: If the problem says "find all solutions" or "is there any valid configuration?" → backtracking. If it says "find the minimum/maximum" → try DP first.
Time Complexity of Backtracking
Backtracking is inherently exponential in the worst case, but pruning reduces actual runtime significantly.
| Problem | Find all permutations of n elements |
| Without pruning | O(n!) — must generate all permutations |
| With pruning | O(n!) — pruning doesn't help for permutations |
| Problem | N-Queens |
| Without pruning | O(n^n) — place queen anywhere in each row |
| With column+diagonal pruning | O(n!) / further optimization ≈ O(n! / e) |
| Problem | Subset Sum |
| Without pruning | O(2^n) — all subsets |
| With sum-based pruning on sorted array | much less in practice |
The general formula for backtracking complexity:
| For permutations | n × (n-1) × (n-2) × ... × 1 = n! |
| For subsets | 2 choices per element = 2^n |
| For Sudoku | up to 9 choices per cell = 9^81 (but pruning reduces this enormously) |
When to Recognize a Backtracking Problem
Look for these keywords in a problem:
- "Find ALL solutions / combinations / permutations"
- "Is there ANY valid arrangement?"
- "Generate all possible..."
- "Can the puzzle be solved?"
- "Find one valid configuration"
Classic backtracking problems:
- N-Queens (place queens without attacking)
- Sudoku solver
- Word search in a 2D grid
- Generating all subsets, permutations, combinations
- Graph coloring
- Crossword puzzle solving
- Constraint satisfaction problems
Common Mistakes in Backtracking
Mistake 1 — Forgetting to Undo the Choice
Mistake 2 — Not Copying the Solution Before Saving
Mistake 3 — Missing Base Case
# Will recurse forever:
def backtrack(state):
for choice in choices:
make_choice(state, choice)
backtrack(state) # Never stops!
undo_choice(state, choice)
# Always define when to stop:
def backtrack(state):
if is_complete(state): # ← Base case
result.append(copy(state))
return
for choice in choices:
make_choice(state, choice)
backtrack(state)
undo_choice(state, choice)Summary
Backtracking is the systematic method of exploring all possibilities by:
- Building solutions incrementally (one piece at a time)
- Exploring each option through recursion
- Undoing choices when they lead to dead ends
- Pruning invalid branches early for efficiency
The three-step pattern — Choose → Explore → Undo — appears in every backtracking solution. Master this pattern and you can solve any backtracking problem.
Backtracking is the right choice when:
- You need all solutions (not just one optimal one)
- The problem involves constraint satisfaction
- Brute force would work but is too slow (pruning helps)
- The problem is a classic "grid puzzle" or "arrangement" type
*Next Lesson: N-Queens Problem*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Backtracking — The Complete Guide to Recursive Exploration with Undo.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, backtracking, introduction, backtracking — the complete guide to recursive exploration with undo
Related Data Structures & Algorithms Topics