The O(n) Club: Sudoku Solver—Backtracking Without Losing Your Sanity
⚡ TL;DR
Solve Sudoku like you mean it—skip brute force, do backtracking! Try numbers 1–9 in each empty cell, validate, recurse, and undo if you must. Java handles the heavy lifting (and the therapy bills):
// Try to solve by filling each empty cell recursively void solveSudoku(char[][] board) { backtrack(board); } boolean backtrack(char[][] board) { // Find next empty cell, try numbers 1-9, backtrack if stuck }
🧠 How Devs Usually Mess This Up
Ah, the classic dev mistake: stacking for-loops to exhaustion and wishing upon a star that Sudoku will just solve itself. Sorry, this isn’t JavaScript—magic won’t save you from forgotten undos or mixing up rows and columns. And if you skip smart pruning, get comfy: your code will run longer than all the Lord of the Rings movies… in slow motion.
🔍 What’s Actually Going On
Think of Sudoku as a dinner party with too many dietary restrictions: each cell wants a unique meal (number), but neighbors in rows, columns, and boxes can’t have repeats. Your job? Seat everyone politely by:
🛠️ PseudoCode
- Find the next empty cell:
- Search for the first ‘.’ and mark it as the target.
- Try filling with numbers 1–9:
- For each option, check row, column, and 3×3 block for violations.
- If valid, place the number and go deeper:
- Assign, recurse, and hope for peace.
- If disaster strikes, reset (backtrack):
- Undo the last guess and keep trying.
- If all are filled—congrats, you win Sudoku!
💻 The Code
public class SudokuSolver {
public void solveSudoku(char[][] board) {
backtrack(board);
}
private boolean backtrack(char[][] board) {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (board[row][col] == '.') {
for (char num = '1'; num <= '9'; num++) {
if (isValid(board, row, col, num)) {
board[row][col] = num;
if (backtrack(board)) {
return true;
}
board[row][col] = '.'; // Undo your optimism
}
}
return false;
}
}
}
return true;
}
private boolean isValid(char[][] board, int row, int col, char num) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == num ||
board[i][col] == num ||
board[(row/3)*3 + i/3][(col/3)*3 + i%3] == num) {
return false;
}
}
return true;
}
}
⚠️ Pitfalls, Traps & Runtime Smacks
- Not cleaning up? Forget to reset
board[row][col]
, and congratulations—you’ve got infinite recursion or bizarre errors. - Row/Col brain farts: Mix up your indices and your solution may look like modern art.
- Skipping optimization: Brute force everything and your CPU fan will double as a hand dryer.
- Complexity: The board is always 9×9, so space is (mercifully) constant. But tough puzzles can send the number of guesses, well, sky-high. So… have snacks ready.
🧠 Interviewer Brain-Tattoo
Backtracking: for when you want recursion, regret, and redemption—all in one stack frame. Drop a guess, undo fast, and act like you saw that solution coming the whole time.