We are given a 9x9 Sudoku board with some cells already filled and others marked with '.'. Our job is to fill every empty cell with a digit from 1 to 9 such that no digit repeats in any row, any column, or any of the nine 3x3 sub-boxes. The board is modified in-place, so we don't return anything.
This is a constraint satisfaction problem. At each empty cell we have up to 9 choices, and many of them are eliminated by the row, column, and box constraints. The solution is to place a digit, move on to the next empty cell, and if we reach a dead end where no digit is valid, undo the choice and try the next digit. This is backtracking.
The constraints are what make the search tractable. A single placement eliminates possibilities in its row, its column, and its box at the same time, which prunes large parts of the search space before we ever explore them.
board.length == 9 and board[i].length == 9 → The board is always exactly 9x9. This is a fixed, small size, so even exponential approaches are feasible as long as we prune aggressively.board[i][j] is a digit or '.' → We only need to fill cells containing '.'. Pre-filled cells are guaranteed to be valid.Classic backtracking solves this directly. Find the first empty cell, try placing digits 1 through 9, and for each digit check whether it violates any Sudoku constraint. If the digit is valid, place it and recursively try to fill the next empty cell. If we get stuck (no digit works for some cell), backtrack by removing the last digit we placed and trying the next option.
The validity check scans the row for a duplicate, scans the column for a duplicate, and scans the 3x3 box for a duplicate. This is correct but does redundant work, since we re-scan the same row, column, and box for every digit we try.
'.'.Input:
The brute force approach scans left to right, top to bottom. The first empty cell is (0,2). For each candidate digit it scans all of row 0, column 2, and the top-left 3x3 box to check validity. It tries '1' and '2', both of which pass the local check but fail deeper in the recursion and get undone. '3' is rejected immediately because row 0 already contains a '3' at (0,1). '4' is valid and, after the recursion fills the remaining 50-odd empty cells without hitting a dead end, leads to the completed board shown below.
Output:
Every digit we try costs a scan of 27 cells for the validity check. The next approach removes that cost by tracking which digits are already used in each row, column, and box, turning each validity check into a constant-time lookup.
The brute force re-scans the board for every validity check. Instead, before solving, precompute three collections of sets. rows[i] stores the digits already present in row i. cols[j] stores the digits in column j. boxes[k] stores the digits in box k, where the box index for cell (r, c) is (r / 3) * 3 + (c / 3).
To check if digit d is valid at position (r, c), we do three set lookups: is d in rows[r], in cols[c], or in boxes[boxIndex]? Each lookup is O(1). When we place a digit, we add it to all three sets. When we backtrack, we remove it from all three.
The three sets stay consistent with the board because every placement adds the digit to all three sets and every backtrack removes it from all three. So a lookup in the sets gives the same answer as a full scan of the row, column, and box would, in O(1) instead of O(27). A placement is valid exactly when the digit is absent from all three sets, which matches the three Sudoku rules.
rows[9], cols[9], boxes[9].rows[r], cols[c], and boxes[(r/3)*3 + c/3].rows[r], cols[c], or boxes[boxIndex], place it, recurse, and backtrack if needed.We still process empty cells in board order. But some cells have only one valid option while others have five or six. The next approach always fills the most constrained cell first, which cuts the number of branches the recursion has to explore.
The previous approach tracked constraints with boolean arrays. Bitmasks make the same checks tighter. For each row, column, and box we store a 9-bit integer where bit i being set means digit (i+1) is already used. To find the available digits for a cell, OR the three bitmasks together and invert the low 9 bits: every remaining set bit is a candidate.
The larger gain comes from the Minimum Remaining Values (MRV) heuristic from constraint satisfaction. Instead of filling empty cells left to right, always pick the empty cell with the fewest valid candidates. A cell with one candidate causes no branching, since there is only one digit to try. Choosing the most constrained cell at each step minimizes the branching factor near the top of the recursion tree, where a wide branch is most expensive.
rowMask[9], colMask[9], boxMask[9], each starting at 0.