Module P-7·16 min read

Systematic exploration with pruning — permutations, subsets, and constraint-satisfaction problems like N-Queens.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module P-7 — Backtracking: Exploring the Solution Space

What this module covers: Some problems can't be solved by a direct formula — they require trying a choice, seeing where it leads, and undoing it if it doesn't work out. This module covers backtracking: recursive exploration (Module P-1) of every possible path through a decision space, pruning branches that can't possibly succeed, and restoring state before trying the next option.


The Shape of Backtracking

Every backtracking algorithm follows the same skeleton: make a choice, recurse into the consequences of that choice, then undo the choice before trying the next one — so the next branch starts from a clean slate, not contaminated by the previous attempt.

typescript

The path.pop() after the recursive call is the entire idea in one line: without it, every subsequent branch of the loop would incorrectly still include a choice from a path that's already been fully explored and abandoned. This "undo before trying the next option" step is what separates backtracking from plain recursive exploration (Module P-1) — it's recursion with an explicit discipline about cleaning up after each attempt.

Analogy: Backtracking is exploring a maze by walking down a corridor, marking it as "tried" as you go. If it's a dead end, you don't teleport back to the start — you walk back out the way you came, un-marking as you retreat, so the next corridor you try starts from a genuinely clean position, not one still cluttered with your last attempt's chalk marks.


Generating All Subsets (the Power Set)

For each element, you have exactly two choices: include it, or don't. Backtracking explores both branches for every element:

typescript

Every element doubles the number of possible subsets (include or exclude), so this produces and visits all 2ⁿ subsets — the O(2ⁿ) complexity class from Module F-1's table, here not as an accidental performance trap (as it was for naive Fibonacci in Module P-1) but as the genuinely correct, unavoidable cost of enumerating every subset, since there are exactly 2ⁿ of them to produce.

Why [...current], not current, gets pushed into result: current is a single array, mutated in place throughout the whole recursion — pushing the reference itself would mean every entry in result ends up pointing at the same array, which keeps changing after being "recorded." Copying it at the moment of recording freezes a snapshot of its contents at that exact instant.


Generating All Permutations

Permutations require a different kind of choice-tracking: instead of "include or exclude," every element must be used exactly once, in every possible order — which means tracking which elements have already been placed.

typescript

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.