101 Logo
onenoughtone

Backtracking Pattern

What is Backtracking?

Backtracking is an algorithmic technique that builds a solution incrementally, abandoning a candidate ("backtracking") as soon as it determines that the candidate cannot lead to a valid solution.

It's essentially a depth-first search of the solution space, where we explore all possible paths and backtrack when we hit a dead end.

When to Use Backtracking

Backtracking is useful when:

  • You need to find all (or some) solutions to a problem
  • The problem can be broken down into a sequence of decisions
  • Each decision leads to a new subproblem
  • You can determine if a partial solution can lead to a valid complete solution

Backtracking Template

  1. Define a recursive function that takes the current state and remaining choices
  2. Check if the current state is a valid solution (base case)
  3. For each possible choice:
    • Make the choice (modify the current state)
    • Recursively explore the resulting state
    • Undo the choice (backtrack) to try other choices

Example: N-Queens Problem

The N-Queens problem asks how to place N queens on an N×N chessboard so that no two queens threaten each other.

function solveNQueens(n) { // Result array to store all valid board configurations const result = []; // Initialize an empty board const board = Array(n).fill().map(() => Array(n).fill('.')); // Helper function to check if a queen can be placed at board[row][col] function isSafe(row, col) { // Check the column for (let i = 0; i < row; i++) { if (board[i][col] === 'Q') { return false; } } // Check upper-left diagonal for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { if (board[i][j] === 'Q') { return false; } } // Check upper-right diagonal for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { if (board[i][j] === 'Q') { return false; } } return true; } // Helper function to convert the board to the required format function addSolution() { const solution = board.map(row => row.join('')); result.push(solution); } // Backtracking function to place queens row by row function backtrack(row) { // If all queens are placed, add the solution if (row === n) { addSolution(); return; } // Try placing a queen in each column of the current row for (let col = 0; col < n; col++) { // If it's safe to place a queen at board[row][col] if (isSafe(row, col)) { // Place the queen board[row][col] = 'Q'; // Recursively place queens in the next row backtrack(row + 1); // Backtrack: remove the queen to try other positions board[row][col] = '.'; } } } // Start the backtracking from the first row backtrack(0); return result; } // Example usage: const solutions = solveNQueens(4); console.log(solutions); // Output: [ // [".Q..", "...Q", "Q...", "..Q."], // ["..Q.", "Q...", "...Q", ".Q.."] // ]

Example: Permutations

Generate all possible permutations of a given array of distinct integers.

function permute(nums) { // Result array to store all permutations const result = []; // Backtracking function function backtrack(current, remaining) { // If there are no more numbers to add, we've found a permutation if (remaining.length === 0) { result.push([...current]); return; } // Try each number in the remaining array for (let i = 0; i < remaining.length; i++) { // Add the current number to our permutation current.push(remaining[i]); // Create a new array without the used number const newRemaining = [...remaining.slice(0, i), ...remaining.slice(i + 1)]; // Recursively generate permutations with the updated arrays backtrack(current, newRemaining); // Backtrack: remove the last added number to try other options current.pop(); } } // Start the backtracking with an empty current array and all numbers in remaining backtrack([], nums); return result; } // Example usage: const nums = [1, 2, 3]; const allPermutations = permute(nums); console.log(allPermutations); // Output: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]

Time and Space Complexity

Time Complexity:

O(b^d), where b is the branching factor (number of choices at each step) and d is the maximum depth of the recursion.

Space Complexity:

O(d), where d is the maximum depth of the recursion, due to the recursion stack.

IntroVisualizePatternsPractice
101 Logo
onenoughtone