Backtracking Pattern
Backtracking: generating subsets
Current subset
[]
Remaining choices
1, 2, 3
Record subset []. Try the remaining choices.
Subsets recorded
[]
Step 1 / 16
Choose → Explore → Undo. Each subset is recorded when its state is visited.
🎯 Imagine This...
Imagine exploring a maze. Choose a path, explore it, then undo the choice to try another route. Backtracking builds candidates and prunes a branch as soon as it violates a constraint.
Try → Failed? → Go Back → Try Again
When Should You Use This Pattern?
- ✓You need to enumerate all valid solutions.
- ✓The problem has constraints that can reject a partial candidate.
- ✓You generate combinations or permutations.
- ✓Examples: N-Queens, Sudoku and maze solving.
📝 Example 1: Generate All Subsets
Given [1, 2, 3], generate all possible subsets (power set).
Subsets.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.*;public class Subsets { public static List<List<Integer>> subsets(int[] nums) { List<List<Integer>> result = new ArrayList<>(); backtrack(nums, 0, new ArrayList<>(), result); return result; } private static void backtrack(int[] nums, int start, List<Integer> current, List<List<Integer>> result) { // Add current subset to result result.add(new ArrayList<>(current)); // Try adding each remaining number for (int i = start; i < nums.length; i++) { current.add(nums[i]); // Choose backtrack(nums, i + 1, current, result); // Explore current.remove(current.size() - 1); // Backtrack (undo) } } public static void main(String[] args) { int[] nums = {1, 2, 3}; List<List<Integer>> result = subsets(nums); System.out.println("All subsets:"); for (List<Integer> subset : result) { System.out.println(subset); } // Output: [], [1], [1,2], [1,2,3], [1,3], [2], [2,3], [3] }}📝 Example 2: N-Queens Problem
Place N queens on an N×N chessboard so that no two queens attack each other.
NQueens.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import java.util.*;public class NQueens { public static List<List<String>> solveNQueens(int n) { List<List<String>> result = new ArrayList<>(); char[][] board = new char[n][n]; // Initialize board with empty spaces for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { board[i][j] = '.'; } } backtrack(board, 0, result); return result; } private static void backtrack(char[][] board, int row, List<List<String>> result) { // Base case: placed all queens if (row == board.length) { result.add(construct(board)); return; } // Try placing queen in each column of current row for (int col = 0; col < board.length; col++) { if (isValid(board, row, col)) { board[row][col] = 'Q'; // Choose backtrack(board, row + 1, result); // Explore board[row][col] = '.'; // Backtrack } } } private static boolean isValid(char[][] board, int row, int col) { // Check column for (int i = 0; i < row; i++) { if (board[i][col] == 'Q') return false; } // Check diagonal (top-left) for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 'Q') return false; } // Check diagonal (top-right) for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) { if (board[i][j] == 'Q') return false; } return true; } private static List<String> construct(char[][] board) { List<String> result = new ArrayList<>(); for (char[] row : board) { result.add(new String(row)); } return result; } public static void main(String[] args) { int n = 4; List<List<String>> solutions = solveNQueens(n); System.out.println("Solutions for " + n + "-Queens:"); for (List<String> solution : solutions) { for (String row : solution) { System.out.println(row); } System.out.println(); } }}📝 Example 3: Generate Valid Parentheses
Generate all combinations of n pairs of well-formed parentheses.
GenerateParentheses.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.*;public class GenerateParentheses { public static List<String> generateParenthesis(int n) { List<String> result = new ArrayList<>(); backtrack("", 0, 0, n, result); return result; } private static void backtrack(String current, int open, int close, int max, List<String> result) { // Base case: used all parentheses if (current.length() == max * 2) { result.add(current); return; } // Add opening parenthesis if we can if (open < max) { backtrack(current + "(", open + 1, close, max, result); } // Add closing parenthesis if valid if (close < open) { backtrack(current + ")", open, close + 1, max, result); } } public static void main(String[] args) { int n = 3; List<String> result = generateParenthesis(n); System.out.println("Valid parentheses for n=" + n + ":"); for (String s : result) { System.out.println(s); } // Output: ((())), (()()), (())(), ()(()), ()()() }}🔑 Key Points to Remember
- 1️⃣Three steps: Choose → Explore → Undo (backtrack)
- 2️⃣Use recursion to explore all possibilities
- 3️⃣Time complexity depends on the search space; generating and copying all subsets takes O(n × 2^n).
- 4️⃣Always undo changes after exploring (backtrack!)
💪 Practice Problems
- • Sudoku Solver
- • Word Search
- • Combination Sum
- • Palindrome Partitioning
- • Letter Combinations of Phone Number
Category sequence
Coding Patterns
Lesson 21 / 21