Backtracking
Backtracking is a systematic algorithm for solving constraint-satisfaction and combinatorial problems by building a solution incrementally, undoing choices that lead to invalid or suboptimal states, and trying alternatives.
Explanation
Backtracking is a depth-first exploration of a decision tree. At each step, you make a choice, explore that choice recursively, and then undo the choice (backtrack) to try another option. The key optimization over brute force is pruning: if you detect that the current partial solution can't possibly lead to a valid complete solution, you abandon it immediately rather than continuing to explore its subtree. The general template is: if the current state is a complete, valid solution, record it and return; if the current state is invalid or can't lead to a solution (prune), return early; otherwise, for each possible next choice, make the choice, recurse, and undo the choice. Classic backtracking problems: N-Queens (place N queens on an N×N board so no two attack each other — for each row, try each column, prune if the queen is attacked), Sudoku solver (for each empty cell, try digits 1-9, prune if any digit violates the rules), generating all permutations of an array (for each position, try each unused element), generating all subsets, word search on a grid (DFS that marks visited cells and unmarks on backtrack), and the combination sum problem. Backtracking time complexity is typically exponential (you're exploring an exponential-sized decision tree), but effective pruning can dramatically reduce the practical running time. The Sudoku solver's decision tree has up to 9^81 leaves in theory but prunes so aggressively that it solves puzzles in milliseconds.
Code Example
javascript// Backtracking: generate all permutations
function permutations(nums) {
const result = [];
function backtrack(current, remaining) {
// Base case: complete permutation
if (remaining.length === 0) {
result.push([...current]);
return;
}
for (let i = 0; i < remaining.length; i++) {
// Make a choice
current.push(remaining[i]);
const next = remaining.filter((_, idx) => idx !== i);
// Recurse
backtrack(current, next);
// Undo the choice (backtrack)
current.pop();
}
}
backtrack([], nums);
return result;
}
console.log(permutations([1, 2, 3]));
// [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
// N-Queens pruning example (key insight)
function isValid(board, row, col) {
for (let r = 0; r < row; r++) {
if (board[r] === col) return false; // same column
if (board[r] - r === col - row) return false; // diagonal
if (board[r] + r === col + row) return false; // anti-diagonal
}
return true;
}
Why It Matters for Engineers
Backtracking problems appear frequently in technical interviews because they test recursive thinking, state management (make/undo choices), and pruning intuition. More importantly, understanding backtracking gives you a systematic approach to any problem that asks "find all valid combinations" or "find one valid arrangement" — patterns that come up in scheduling, configuration generation, and constraint solving. Backtracking also teaches the crucial debugging skill of visualizing a decision tree: when your recursive solution produces wrong results, drawing out the states and the choices at each node reveals where the logic diverges from what you intended.
Related Terms
Recursion · Depth-First Search · Dynamic Programming · Greedy Algorithm
Learn This In Practice
Go deeper with the full module on Beyond Vibe Code.
Algorithms Fundamentals → →