Skip to content

Backtracking

Backtracking explores all potential solutions by building candidates incrementally and pruning branches that can't lead to a valid solution. It's DFS with undo. Template: choose → explore → unchoose. Use for: permutations, combinations, subsets, N-Queens, Sudoku solver, word search. Time complexity is often exponential (O(2^n) or O(n!)).

Key Concepts

Deep Dive: Backtracking Template
void backtrack(result, currentPath, choices) {
    if (isComplete(currentPath)) {
        result.add(new ArrayList<>(currentPath));  // Deep copy!
        return;
    }
    for (choice : choices) {
        if (isValid(choice)) {
            currentPath.add(choice);       // Choose
            backtrack(result, currentPath, remainingChoices);  // Explore
            currentPath.removeLast();      // Unchoose (backtrack)
        }
    }
}
Deep Dive: Subsets, Permutations, Combinations

Subsets:

public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    backtrack(result, new ArrayList<>(), nums, 0);
    return result;
}
private void backtrack(List<List<Integer>> result, List<Integer> path, int[] nums, int start) {
    result.add(new ArrayList<>(path));
    for (int i = start; i < nums.length; i++) {
        path.add(nums[i]);
        backtrack(result, path, nums, i + 1);
        path.removeLast();
    }
}

Permutations:

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    boolean[] used = new boolean[nums.length];
    backtrack(result, new ArrayList<>(), nums, used);
    return result;
}
private void backtrack(List<List<Integer>> result, List<Integer> path, int[] nums, boolean[] used) {
    if (path.size() == nums.length) { result.add(new ArrayList<>(path)); return; }
    for (int i = 0; i < nums.length; i++) {
        if (used[i]) continue;
        used[i] = true;
        path.add(nums[i]);
        backtrack(result, path, nums, used);
        path.removeLast();
        used[i] = false;
    }
}

Combination Sum:

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    List<List<Integer>> result = new ArrayList<>();
    backtrack(result, new ArrayList<>(), candidates, target, 0);
    return result;
}
private void backtrack(List<List<Integer>> result, List<Integer> path, int[] nums, int remaining, int start) {
    if (remaining == 0) { result.add(new ArrayList<>(path)); return; }
    for (int i = start; i < nums.length; i++) {
        if (nums[i] > remaining) continue;  // Prune
        path.add(nums[i]);
        backtrack(result, path, nums, remaining - nums[i], i);
        path.removeLast();
    }
}

Common Interview Questions
  • Subsets / Subsets II (with duplicates)
  • Permutations / Permutations II
  • Combination Sum I/II/III
  • Letter Combinations of a Phone Number
  • N-Queens
  • Sudoku Solver
  • Word Search
  • Generate Parentheses
  • Palindrome Partitioning