Backtracking

Try a choice, check it's still legal, go deeper — and when you hit a dead end, undo and try the next option. The pattern behind subsets, permutations and every constraint puzzle.

backtrackingrecursioncombinatorics

The idea, with zero jargon

You're in a maze. At every junction you pick a corridor and walk. Hit a dead end? You walk back to the junction and take the next corridor. You never teleport, you never clone yourself — one walker, exploring everything, by remembering to undo.

That's the entire algorithm:

  1. Choose — pick one of the available options.
  2. Explore — go deeper with that choice made.
  3. Un-choose — undo the choice, so the next option starts from a clean slate.

The un-choose step is what beginners forget, and it's the whole trick: it's what lets the same path/board/array be reused for every branch instead of copying it at every step.

Watch it run: N-Queens

The classic constraint puzzle: place queens so none can attack another. Watch three things — choices being made (green), illegal squares being rejected before going deeper (red ✕), and the backtrack itself: a queen being lifted off the board when everything below it failed.

Backtracking — N-Queenstime O(n!) prunedspace O(n)

1/32Place 4 queens on a 4×4 board so none can attack another (no shared row, column or diagonal). Brute force would test every arrangement; backtracking abandons bad ones early. One queen per row — row by row.

board size

Watch it run: subsets

Most backtracking interview problems are secretly this: walk the items left to right, and for each one make a yes/no decision. Every route through the decisions produces one subset.

Backtracking — all subsetstime O(2ⁿ)space O(n)
?
1
?
2
?
3
subsets found (0)
(none yet — reach the end of the decisions first)

1/24List every subset of {1, 2, 3}. Walk the numbers left to right; for each one make a yes/no decision: take it, or leave it. 3 decisions → 2^3 = 8 subsets.

The template

Build a candidate incrementally; at each step choose an option, explore deeper, then un-choose (undo) to try the next. It's DFS over the space of partial solutions — the "graph" is imaginary: nodes are partial answers, edges are choices.

Python
def subsets(nums):
    res, path = [], []
    def backtrack(start):
        res.append(path[:])              # every node is a valid subset
        for i in range(start, len(nums)):
            path.append(nums[i])         # choose
            backtrack(i + 1)             # explore (i+1 ⇒ no reuse, no dupes)
            path.pop()                   # un-choose
    backtrack(0)
    return res

The start index is what prevents duplicate subsets; for permutations you'd instead track a used[] set and iterate all indices.

Knowing the shape

ProblemBranch onAvoid dupes via
Subsetsinclude/skip each itemstart index
Combinations (k of n)pick next ≥ startstart index
Permutationsany unused itemused[] flags
Partition / N-Queens / Sudokueach valid placementconstraint check

How to recognize a backtracking problem

The wording gives it away. Reach for backtracking when the problem says:

  • "all subsets / all permutations / all combinations / every way to…" → you're asked to enumerate, not to find one best answer.
  • "place / arrange / assign … such that no two conflict" → constraint puzzle (N-Queens, Sudoku, graph coloring).
  • "can you split / partition the input into groups that…" → try assignments, undo on failure.
  • The input is tiny (n ≤ ~15). Exponential is expected; the question is whether your recursion is clean and your pruning is real.

If instead it asks for the count of ways or the best value — and the same sub-questions repeat — that's dynamic programming: DP remembers answers, backtracking enumerates paths.

Pruning is the whole point

Naive enumeration is O(2ⁿ) or O(n!). Pruning — cutting branches that can't lead to a valid/better solution — is what makes it pass. You saw it in the N-Queens player: the red ✕ squares were rejected before recursing, killing whole subtrees of doomed arrangements in one comparison. Sort to enable early termination, skip equal siblings to dedupe, and check constraints before recursing.

Backtracking is viable when n is tiny

If the constraints say n ≤ ~12–15, exponential backtracking is expected — the interviewer wants a clean recursion with correct pruning, not a polynomial trick. The input size is the hint (see the DSA study plan).

Think one through

Think it through: PermutationsMedium — LeetCode 460/4 stages

PROBLEMGiven an array of distinct numbers like [1, 2, 3], return every possible ordering: [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1].

  1. 1

    Spot the pattern

    What word in the problem tells me which tool to grab?

  2. 2

    Frame the decisions

    Building one permutation step by step — what is the choice at each step?

    unlocks after the stage above
  3. 3

    Write the skeleton

    Where exactly do choose, explore, and un-choose go?

    unlocks after the stage above
  4. 4

    Check the cost, test the edges

    How much work is this, and what inputs could break it?

    unlocks after the stage above
Check yourself0/3 answered

1. In choose → explore → un-choose, what breaks if you forget the un-choose step?

2. A problem says: 'count the number of ways to climb n stairs taking 1 or 2 steps'. Backtracking or DP?

3. Why does checking N-Queens conflicts BEFORE recursing matter so much?

Practice — climb the ladder

Every backtracking solution is the same skeleton: choose → explore → un-choose. The only things that change are the choice list and the pruning.

Practice ladder: Backtracking0/9 solved

Climb in order — every rung assumes the one above it. Solve on LeetCode, then tick it here; progress is saved on this device.

Warm-up

enumerate without pruning
  1. SubsetsMedium

    Include/exclude branching — the decision tree in its purest form.

  2. Cartesian-product recursion — one digit per level, combine on the way down.

Core

dedup, reuse, and board walks
  1. Used-set bookkeeping — order matters now; un-choose restores state EXACTLY.

  2. Reuse allowed + start-index discipline to avoid duplicate combinations.

  3. Pruning by invariant — never place a close past its open count.

  4. Grid backtracking — mark the cell, explore 4 ways, UNMARK; the un-choose drill.

  5. Partition-point recursion — cut positions as choices, validity as pruning.

Stretch

constraint propagation at full power
  1. Column/diagonal sets as O(1) constraint checks — pruning as the main event.

  2. The full search-with-constraints experience — choose the cell, try 9, backtrack.