---
title: "Backtracking"
url: https://algopath.pro/patterns/backtracking
language: en
summary: "Make a choice, recurse, and then take the choice back. That undo is what lets a single array hold every candidate in turn."
updated: 2026-08-24
---

# Backtracking

Make a choice, recurse, and then take the choice back. That undo is what lets a single array hold every candidate in turn.

## How does Backtracking work?

Keep one array holding the choices made so far. It is the path down the tree.

At each level, loop over the options still available. Every option is one branch.

Push the option, then call yourself for the next level. Nothing else changes.

When that call returns, pop the option off again. The array is exactly as it was.

At the bottom, record a copy of the path. Recording the array itself stores a shared buffer.

Cut a branch as soon as it cannot work. That pruning is where the speed comes from.

- `path = []` Listing the subsets of [1, 2]. The empty set already counts.
- `path = [1]` Take the 1 and go one level down.
- `path = [1, 2]` Take the 2 as well. This branch is finished.
- `path = [1], then []` Two pops undo both choices. The array is empty again.
- `path = [2]` Skip the 1 and take the 2. Four subsets in total.

## When should you use Backtracking?

- generate all subsets/permutations/combinations
- n is small (roughly n <= 12-20), exponential search is acceptable
- make a choice, recurse, then undo it before trying the next choice
- place items under constraints and back off on conflict (N-Queens, Sudoku)
- return every valid arrangement, not just one

## What is Backtracking confused with?

- **Recursion** - Recursion goes down and comes back. Backtracking also puts the state back as it returns.
- **Recursion with memoization** - A cache pays off when arguments repeat. Down a path of distinct choices they rarely do.
- **Dynamic programming (1-D)** - DP counts or optimises without listing anything. Backtracking is for when you need the arrangements.
- **Matrix word search (grid DFS/backtracking)** - That is this pattern on a grid. The choice there is which neighbour to step into.

## What is the time and space complexity of Backtracking?

The output is exponential, so n stays small. Subsets of 20 items are 1e6, permutations of 10 are 3.6e6.

## A worked example of Backtracking

### Every combination that hits a target

You get distinct positive numbers and a target. List every combination that adds up to it.

A number may be used as many times as you like.

At each level, try every number from the current index onward.

Starting at the current index stops the same combination appearing reordered. A negative remainder cuts the branch.

```javascript
function combinationSum(candidates, target) {
    const result = [];
    const path = [];

    function walk(start, left) {
        if (left === 0) {
            result.push([...path]); // a copy, never the live array
            return;
        }
        if (left < 0) return; // pruned: this branch cannot recover

        for (let i = start; i < candidates.length; i++) {
            path.push(candidates[i]);
            walk(i, left - candidates[i]); // i, not i + 1: reuse is allowed
            path.pop();                    // undo before the next option
        }
    }

    walk(0, target);
    return result;
}
```

## Common mistakes with Backtracking

- **Storing the live path in the results** Every result then points at the same array. Push a copy of it instead.
- **Forgetting to undo the choice** The path grows and never shrinks. Later branches then inherit choices that were not theirs.
- **Starting the inner loop at zero** The same combination then appears in every possible order. Pass the current index down.
- **Never pruning a branch** Without an early exit the entire tree gets explored. Most of these are only fast because of the cut.

## Which interview problems use Backtracking?

- **Subsets** Two options per element: take it or skip it.
- **Permutations** Every unused element is an option at each level.
- **Combination sum** The index passed down decides whether reuse is allowed.
- **N-queens** Prune on the column and on both diagonals.
- **Word search** The grid is the tree, and neighbours are the choices.
- **Palindrome partitioning** Cut at every position whose prefix is a palindrome.
- **Sudoku solver** Nine options per empty cell, pruned by the rules.

## JavaScript

```javascript
function backtrack(path, choices, result) {
    if (path.length === choices.length) { // or another stop condition
        result.push([...path]);
        return;
    }
    for (const choice of choices) {
        path.push(choice); // choose
        backtrack(path, choices, result); // explore
        path.pop(); // undo
    }
}
```

## Python

```python
def backtrack(path, choices, result):
    if len(path) == len(choices):  # or another stop condition
        result.append(path[:])
        return
    for choice in choices:
        path.append(choice)  # choose
        backtrack(path, choices, result)  # explore
        path.pop()  # undo
```

## PHP

```php
function backtrack(array &$path, array $choices, array &$result): void {
    if (count($path) === count($choices)) {
        $result[] = $path;
        return;
    }
    foreach ($choices as $choice) {
        $path[] = $choice; // choose
        backtrack($path, $choices, $result); // explore
        array_pop($path); // undo
    }
}
```
