Sudoku Solver
Fill the empty cells of a 9×9 Sudoku so each row, column, and 3×3 box holds digits 1–9 exactly once.
Open on LeetCode ↗Intuition
Take the first empty cell, try each digit that doesn't clash with its row, column, or box, and recurse. A cell with no legal digit proves an earlier guess wrong — undo and try the next. Constraint checks kill branches so fast the 9^81 space collapses.
Constraint backtracking on a grid: find an empty cell, try each legal digit, recurse, and undo on failure. The box index arithmetic — 3 * (r // 3) for the block's origin — is the piece worth memorising, and returning a boolean lets the recursion stop the instant one solution is complete.
Approach
Scan for the next blank
Solve cells in reading order; the recursion's state is just 'first blank from here'.
Try digits with a validity check
A digit is legal if absent from the cell's row, column, and 3×3 box (box index = (r//3)*3 + c//3).
Recurse, undo on failure
Place, recurse; if the sub-board is unsolvable, erase and continue. True bubbles up when no blanks remain.
Solution & live demo
Common pitfalls
Returning False after the digit loop but outside it
for ch in "123456789":
...
continue # try the next cellfor ch in "123456789":
...
return FalseIf no digit fits this cell, the current partial board is unsolvable and the caller must backtrack. Moving on to another cell explores a dead branch forever instead of retreating.
Computing the box origin without flooring
br, bc = r // 3, c // 3
br, bc = 3 * (r // 3), 3 * (c // 3)
r // 3 gives the box number (0–2), not the row where that box begins. Without multiplying back by 3 the scan checks cells from the top-left corner of the grid rather than the relevant block.
Not clearing the cell when a branch fails
board[r][c] = ch if solve(): return True
board[r][c] = ch if solve(): return True board[r][c] = "."
A failed digit left in place poisons every later attempt — the cell reads as filled, so it's skipped, and the constraint checks see a value that was rejected. Undo is what makes it backtracking.
Edge cases
No blank found → immediately true.
Cells with a single legal digit fall out instantly, cascading constraints — that's why real puzzles solve in milliseconds.