272. Sudoku Solver
๐ LeetCode Problem: 37. Sudoku Solver
๐ Difficulty: Hard
๐ท๏ธ Topics: Array, Backtracking, Matrix
Problem Statement
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9must occur exactly once in each row. - Each of the digits
1-9must occur exactly once in each column. - Each of the digits
1-9must occur exactly once in each of the 93x3sub-boxes of the grid.
The '.' character indicates empty cells.
Example 1:
Input: board =
[["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]]
Output:
[["5","3","4","6","7","8","9","1","2"],
["6","7","2","1","9","5","3","4","8"],
["1","9","8","3","4","2","5","6","7"],
["8","5","9","7","6","1","4","2","3"],
["4","2","6","8","5","3","7","9","1"],
["7","1","3","9","2","4","8","5","6"],
["9","6","1","5","3","7","2","8","4"],
["2","8","7","4","1","9","6","3","5"],
["3","4","5","2","8","6","1","7","9"]]
Constraints:
- board.length == 9
- board[i].length == 9
- board[i][j] is a digit 1-9 or '.'
- It is guaranteed that the input board has only one solution.
๐ ELI5: The Simple Idea!
Think of filling a Sudoku puzzle step by step:
You have a 9ร9 grid with some numbers filled in.
You need to fill the empty cells (marked with '.').
Rules:
1. Each row must have 1-9 (no repeats)
2. Each column must have 1-9 (no repeats)
3. Each 3ร3 box must have 1-9 (no repeats)
Strategy:
1. Find an empty cell
2. Try placing 1, 2, 3, ... 9
3. For each number, check if it's valid (doesn't violate rules)
4. If valid, place it and move to next empty cell
5. If stuck (no valid number), BACKTRACK - undo and try different number
6. Repeat until board is complete!
Example - Filling one cell:
Board:
5 3 . | . 7 . | . . .
6 . . | 1 9 5 | . . .
. 9 8 | . . . | . 6 .
------+-------+------
8 . . | . 6 . | . . 3
4 . . | 8 . 3 | . . 1
7 . . | . 2 . | . . 6
------+-------+------
. 6 . | . . . | 2 8 .
. . . | 4 1 9 | . . 5
. . . | . 8 . | . 7 9
Empty cell at (0,2):
Try 1? Check row 0: has 5,3,7 โ 1 valid โ
Check col 2: has 8 โ 1 valid โ
Check box 0: has 5,3,6,9,8 โ 1 valid โ
Place 1? Try it, move forward!
If later we get stuck:
Backtrack, remove 1, try 2, 3, ... etc.
๐จ Visual Understanding
The 9ร9 Grid Structure
Grid indices (row, col):
0 1 2 3 4 5 6 7 8
0 [5] [3] [.] [.] [7] [.] [.] [.] [.]
1 [6] [.] [.] [1] [9] [5] [.] [.] [.]
2 [.] [9] [8] [.] [.] [.] [.] [6] [.]
3 [8] [.] [.] [.] [6] [.] [.] [.] [3]
4 [4] [.] [.] [8] [.] [3] [.] [.] [1]
5 [7] [.] [.] [.] [2] [.] [.] [.] [6]
6 [.] [6] [.] [.] [.] [.] [2] [8] [.]
7 [.] [.] [.] [4] [1] [9] [.] [.] [5]
8 [.] [.] [.] [.] [8] [.] [.] [7] [9]
The 9 Sub-Boxes (3ร3 each)
Box numbering:
Box 0 | Box 1 | Box 2
------+-------+------
Box 3 | Box 4 | Box 5
------+-------+------
Box 6 | Box 7 | Box 8
Box 0 (top-left): Box 4 (center):
5 3 . 8 . 3
6 . . . . .
. 9 8 . 2 .
Box index calculation:
boxIndex = (row / 3) * 3 + (col / 3)
Example: cell (4,5) โ box = (4/3)*3 + (5/3) = 1*3 + 1 = 4 โ
๐ฏ CRITICAL CONCEPT: Box Starting Position Calculation
This is the MOST CONFUSING part of Sudoku! Let me break it down step by step:
The Grid Layout with Coordinates
The 9ร9 grid is divided into 9 boxes of 3ร3:
Col: 0 1 2 | 3 4 5 | 6 7 8
Row 0: [0][0][0] [1][1][1] [2][2][2] โ Box numbers in each cell
Row 1: [0][0][0] [1][1][1] [2][2][2]
Row 2: [0][0][0] [1][1][1] [2][2][2]
----+---------+---------+---------
Row 3: [3][3][3] [4][4][4] [5][5][5]
Row 4: [3][3][3] [4][4][4] [5][5][5]
Row 5: [3][3][3] [4][4][4] [5][5][5]
----+---------+---------+---------
Row 6: [6][6][6] [7][7][7] [8][8][8]
Row 7: [6][6][6] [7][7][7] [8][8][8]
Row 8: [6][6][6] [7][7][7] [8][8][8]
Notice the pattern:
Rows 0-2: Boxes 0, 1, 2
Rows 3-5: Boxes 3, 4, 5
Rows 6-8: Boxes 6, 7, 8
Understanding the Box Calculation - Step by Step
Question: Given a cell at (row, col), which 3ร3 box does it belong to?
Example 1: Cell at (4, 5)
Step 1: Which BOX ROW GROUP?
Row 4 is in which group of 3?
Rows 0-2: Group 0
Rows 3-5: Group 1 โ Row 4 is here!
Rows 6-8: Group 2
Formula: row / 3 = 4 / 3 = 1 (integer division)
โ Box row group = 1
Step 2: Which BOX COLUMN GROUP?
Col 5 is in which group of 3?
Cols 0-2: Group 0
Cols 3-5: Group 1 โ Col 5 is here!
Cols 6-8: Group 2
Formula: col / 3 = 5 / 3 = 1 (integer division)
โ Box col group = 1
Step 3: What's the STARTING POSITION of this box?
Box row group 1 starts at row: 1 ร 3 = 3
Box col group 1 starts at col: 1 ร 3 = 3
โ Box starts at (3, 3)
The 3ร3 box is:
Col: 3 4 5
Row 3: [ ][ ][ ]
Row 4: [ ][X][ ] โ Our cell (4,5)
Row 5: [ ][ ][ ]
Visual Walkthrough:
Step-by-step for cell (4, 5):
1. row / 3 = 4 / 3 = 1
"Cell is in box row group 1"
Visualize:
Group 0: rows 0,1,2
Group 1: rows 3,4,5 โ HERE!
Group 2: rows 6,7,8
2. col / 3 = 5 / 3 = 1
"Cell is in box column group 1"
Visualize:
Group 0: cols 0,1,2
Group 1: cols 3,4,5 โ HERE!
Group 2: cols 6,7,8
3. Convert group to starting position:
boxRow = 1 ร 3 = 3 (group 1 starts at row 3)
boxCol = 1 ร 3 = 3 (group 1 starts at col 3)
Full board visualization:
0 1 2 | 3 4 5 | 6 7 8
0 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
1 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
2 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
-----------+---------+---------
3 [ ][ ][ ] [S][ยท][ยท] [ ][ ][ ] S = Starting position (3,3)
4 [ ][ ][ ] [ยท][X][ยท] [ ][ ][ ] X = Our cell (4,5)
5 [ ][ ][ ] [ยท][ยท][ยท] [ ][ ][ ] ยท = Other cells in box
-----------+---------+---------
6 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
7 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
8 [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
4. Loop through the 3ร3 box:
for (r = 3; r < 3+3; r++) // rows 3,4,5
for (c = 3; c < 3+3; c++) // cols 3,4,5
Check board[r][c]
More Examples to Solidify Understanding
Example 2: Cell at (0, 0)
Step 1: row / 3 = 0 / 3 = 0 โ Box row group 0
Step 2: col / 3 = 0 / 3 = 0 โ Box col group 0
Step 3: boxRow = 0 ร 3 = 0, boxCol = 0 ร 3 = 0
Starting position: (0, 0)
The box:
Col: 0 1 2
Row 0: [X][ ][ ] โ Our cell
Row 1: [ ][ ][ ]
Row 2: [ ][ ][ ]
Loop: r = 0 to 2, c = 0 to 2 โ
Example 3: Cell at (8, 7)
Step 1: row / 3 = 8 / 3 = 2 โ Box row group 2
Step 2: col / 3 = 7 / 3 = 2 โ Box col group 2
Step 3: boxRow = 2 ร 3 = 6, boxCol = 2 ร 3 = 6
Starting position: (6, 6)
The box:
Col: 6 7 8
Row 6: [ ][ ][ ]
Row 7: [ ][X][ ] โ Our cell (8,7) is in this box
Row 8: [ ][ ][ ]
Loop: r = 6 to 8, c = 6 to 8 โ
Example 4: Cell at (1, 4)
Step 1: row / 3 = 1 / 3 = 0 โ Box row group 0
Step 2: col / 3 = 4 / 3 = 1 โ Box col group 1
Step 3: boxRow = 0 ร 3 = 0, boxCol = 1 ร 3 = 3
Starting position: (0, 3)
The box:
Col: 3 4 5
Row 0: [ ][ ][ ]
Row 1: [ ][X][ ] โ Our cell
Row 2: [ ][ ][ ]
Loop: r = 0 to 2, c = 3 to 5 โ
Why This Formula Works - The Pattern
The KEY insight:
1. Division by 3 tells us WHICH group (0, 1, or 2)
row / 3 โ which horizontal band of boxes
col / 3 โ which vertical band of boxes
2. Multiply by 3 to get STARTING index
group 0 โ starts at 0
group 1 โ starts at 3
group 2 โ starts at 6
Pattern: group ร 3 = starting index
3. Then loop +3 from starting position
Starting at 0 โ check 0,1,2
Starting at 3 โ check 3,4,5
Starting at 6 โ check 6,7,8
Visual Pattern:
Group 0: 0 ร 3 = 0 โ check indices 0,1,2
Group 1: 1 ร 3 = 3 โ check indices 3,4,5
Group 2: 2 ร 3 = 6 โ check indices 6,7,8
Common Confusion - Why NOT Just row/3 and col/3?
โ WRONG: Why can't we just use row/3 and col/3 directly?
If cell is at (4, 5):
row / 3 = 1
col / 3 = 1
If we loop: for (r = 1; r < 1+3; r++)
โ r goes from 1 to 3 (checks rows 1,2,3)
But cell (4,5) is in rows 3,4,5! โ
We'd be checking the WRONG box!
โ CORRECT: Multiply by 3 first!
boxRow = (row / 3) ร 3 = 1 ร 3 = 3
boxCol = (col / 3) ร 3 = 1 ร 3 = 3
Loop: for (r = 3; r < 3+3; r++)
โ r goes from 3 to 5 (checks rows 3,4,5) โ
Now checking the CORRECT box!
Memory Aid - The "Divide, Multiply, Add" Pattern
Think of it as a 3-step process:
1. DIVIDE by 3: Find which group (0, 1, or 2)
row / 3 = which box row group
col / 3 = which box col group
2. MULTIPLY by 3: Convert group to starting index
(row / 3) ร 3 = starting row of box
(col / 3) ร 3 = starting col of box
3. ADD 3: Loop through 3ร3 box
for (r = start; r < start + 3; r++)
for (c = start; c < start + 3; c++)
Mnemonic: "Divide to find, Multiply to start, Add to finish!"
Complete Visual Example
Cell at (7, 2) - Where is its 3ร3 box?
Full board:
Col: 0 1 2 | 3 4 5 | 6 7 8
Row 0: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
Row 1: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
Row 2: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
----+---------+---------+---------
Row 3: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
Row 4: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
Row 5: [ ][ ][ ] [ ][ ][ ] [ ][ ][ ]
----+---------+---------+---------
Row 6: [S][ยท][ยท] [ ][ ][ ] [ ][ ][ ] โ Box starts here
Row 7: [ยท][ยท][X] [ ][ ][ ] [ ][ ][ ] โ Our cell
Row 8: [ยท][ยท][ยท] [ ][ ][ ] [ ][ ][ ]
Calculation:
row / 3 = 7 / 3 = 2 (group 2)
col / 3 = 2 / 3 = 0 (group 0)
boxRow = 2 ร 3 = 6
boxCol = 0 ร 3 = 0
Loop: r from 6 to 8, c from 0 to 2
Checks box in bottom-left corner! โ
Constraint Checking Visual
When placing '4' at cell (0,2):
ROW CHECK (row 0):
[5][3][4][ ][ ][ ][ ][ ][ ]
โ โ โ
Check: Does row 0 already have 4?
5, 3 โ No 4 found โ
COLUMN CHECK (col 2):
[4] (0,2) โ Placing here
[ ] (1,2)
[8] (2,2)
[ ] (3,2)
[ ] (4,2)
[ ] (5,2)
[ ] (6,2)
[ ] (7,2)
[ ] (8,2)
Check: Does col 2 already have 4?
Only 8 โ No 4 found โ
BOX CHECK (box 0):
5 3 4 โ Placing here
6 . .
. 9 8
Check: Does box 0 already have 4?
5,3,6,9,8 โ No 4 found โ
All checks pass โ 4 is VALID! โ
๐จ How Tracking Works - Visual Step by Step
Complete State Tracking - Simplified Example
Simplified 4ร4 Sudoku for clarity (same logic applies to 9ร9):
Initial Board:
1 . | . 4
. 3 | 4 .
----+----
. 4 | 2 .
4 . | . 1
Goal: Fill all '.' cells
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
STEP 1: Find first empty cell (0,1)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Board state:
1 [?] | . 4
. 3 | 4 .
-----+-----
. 4 | 2 .
4 . | . 1
Position: (0,1)
Try values: 1, 2, 3, 4
Try 1:
Row 0 check: has 1 โ (invalid)
Try 2:
Row 0 check: no 2 โ
Col 1 check: no 2 โ
Box 0 check: no 2 โ
โ Place 2! โ
Board after placing 2:
1 [2] | . 4
. 3 | 4 .
-----+-----
. 4 | 2 .
4 . | . 1
Move to next empty cell!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
STEP 2: Next empty cell (0,2)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Board state:
1 2 | [?] 4
. 3 | 4 .
----+------
. 4 | 2 .
4 . | . 1
Position: (0,2)
Try values: 1, 2, 3, 4
Try 1:
Row 0: has 1 โ
Try 2:
Row 0: has 2 โ
Try 3:
Row 0: no 3 โ
Col 2: no 3 โ
Box 1: has 4, checking 3... no 3 โ
โ Place 3! โ
Board after placing 3:
1 2 | [3] 4
. 3 | 4 .
----+------
. 4 | 2 .
4 . | . 1
Continue...
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
EXAMPLE OF BACKTRACKING - When Stuck
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Suppose we reach this state:
1 2 | 3 4
2 3 | 4 1
----+----
3 4 | 2 [?]
4 1 | . 2
Position: (2,3)
Try values: 1, 2, 3, 4
Try 1:
Row 2: no 1 โ
Col 3: has 4,1,2 โ no 1... wait, check again
Col 3: 4,1,?,2 โ has 1 โ
Try 2:
Row 2: has 2 โ
Try 3:
Row 2: has 3 โ
Try 4:
Row 2: has 4 โ
ALL VALUES TRIED, NONE VALID! ๐ฑ
BACKTRACK! โฌ
๏ธ
Go back to previous cell (2,2)
Remove the value we placed there
Try next value
This is the essence of backtracking!
Real 9ร9 Tracking - First Few Steps
Initial board (first 3 rows):
0 1 2 | 3 4 5 | 6 7 8
0 [5] [3] [.] [.] [7] [.] [.] [.] [.]
1 [6] [.] [.] [1] [9] [5] [.] [.] [.]
2 [.] [9] [8] [.] [.] [.] [.] [6] [.]
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Cell (0,2): First empty cell
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Try 1:
Row 0: [5,3,_,_,7,_,_,_,_] โ no 1 โ
Col 2: [_,_,8,_,_,_,_,_,_] โ no 1 โ
Box 0: [5,3,_,6,_,_,_,9,8] โ no 1 โ
Valid? Seems OK, but let's check more...
Actually, let me try 4:
Row 0: [5,3,_,_,7,_,_,_,_] โ no 4 โ
Col 2: [_,_,8,_,_,_,_,_,_] โ no 4 โ
Box 0: [5,3,_,6,_,_,_,9,8] โ no 4 โ
Valid? YES โ
Place 4:
Board:
0 1 2 | 3 4 5 | 6 7 8
0 [5] [3] [4] [.] [7] [.] [.] [.] [.]
1 [6] [.] [.] [1] [9] [5] [.] [.] [.]
2 [.] [9] [8] [.] [.] [.] [.] [6] [.]
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Cell (0,3): Next empty cell
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Try 1:
Row 0: [5,3,4,_,7,_,_,_,_] โ no 1 โ
Col 3: [_,1,_,_,8,_,_,4,_] โ has 1 โ
Invalid!
Try 2:
Row 0: [5,3,4,_,7,_,_,_,_] โ no 2 โ
Col 3: [_,1,_,_,8,_,_,4,_] โ no 2 โ
Box 1: [_,7,_,1,9,5,_,_,_] โ no 2 โ
Valid? YES โ
Place 2:
Board:
0 1 2 | 3 4 5 | 6 7 8
0 [5] [3] [4] [2] [7] [.] [.] [.] [.]
1 [6] [.] [.] [1] [9] [5] [.] [.] [.]
2 [.] [9] [8] [.] [.] [.] [.] [6] [.]
... and so on until all cells filled!
Backtracking in Action
Suppose at some point we have:
Board state with cell (5,7) being filled
Try 1: Invalid (row conflict)
Try 2: Invalid (col conflict)
Try 3: Invalid (box conflict)
Try 4: Invalid (row conflict)
Try 5: Invalid (col conflict)
Try 6: Invalid (box conflict)
Try 7: Invalid (row conflict)
Try 8: Invalid (col conflict)
Try 9: Invalid (box conflict)
ALL 9 VALUES FAILED! ๐ฑ
BACKTRACK STEPS:
1. Mark cell (5,7) as empty again: board[5][7] = '.'
2. Return false to caller
3. Caller is working on cell (5,6)
4. Caller tries next value at (5,6)
5. If all values at (5,6) fail, backtrack further!
Backtracking chain:
Cell (5,7) fails โ Backtrack to (5,6)
Cell (5,6) exhausted โ Backtrack to (5,5)
Cell (5,5) tries next value โ Move forward again
Keep backtracking until find valid path!
Visual Flow Chart
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Start: Find next empty cell โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Found empty cell? โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ NO โ YES โ
โ โ SOLVED! โ โ โ Try values 1-9 โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ For value = 1 to 9: โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Is value valid? โ
โ (Check row, col, box) โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโค
โ NO โ YES โ
โ โ Try next โ โ Place value โ
โโโโโโโโโโโโโโโโดโโโโโโโโฌโโโโโโโโ
โ
โ
โโโโโโโโโโโโโโโโโโโโ
โ Recurse to next โ
โ empty cell โ
โโโโโโโโโโโฌโโโโโโโโโค
โ Success โ Failed โ
โ โ Done! โ โ Undo โ
โโโโโโโโโโโดโโโโโฌโโโโ
โ
โ
โโโโโโโโโโโโโโโโ
โ BACKTRACK: โ
โ Remove value โ
โ Try next โ
โโโโโโโโโโโโโโโโ
๐จ Understanding Box Calculation - The Tricky Part!
Why Box Calculation is Confusing
The formula: boxRow = (row / 3) * 3
What does this even mean? ๐ค
Let's break it down step by step!
Visual Understanding - The 9 Boxes
The 9ร9 Sudoku board is divided into 9 boxes (3ร3 each):
Columns: 0 1 2 | 3 4 5 | 6 7 8
Rows:
0 โโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโ
1 โ Box 0 โ Box 1 โ Box 2 โ
2 โโโโโโโโโโผโโโโโโโโโผโโโโโโโโโค
3 โ Box 3 โ Box 4 โ Box 5 โ
4 โโโโโโโโโโผโโโโโโโโโผโโโโโโโโโค
5 โ Box 6 โ Box 7 โ Box 8 โ
6 โโโโโโโโโโดโโโโโโโโโดโโโโโโโโโ
7
8
Box boundaries:
Box 0: rows [0,1,2], cols [0,1,2]
Box 1: rows [0,1,2], cols [3,4,5]
Box 2: rows [0,1,2], cols [6,7,8]
Box 3: rows [3,4,5], cols [0,1,2]
Box 4: rows [3,4,5], cols [3,4,5] โ Center box
Box 5: rows [3,4,5], cols [6,7,8]
Box 6: rows [6,7,8], cols [0,1,2]
Box 7: rows [6,7,8], cols [3,4,5]
Box 8: rows [6,7,8], cols [6,7,8]
Step-by-Step: Finding Box Start
GOAL: Given any cell (row, col), find the TOP-LEFT corner of its box
Example 1: Cell (4, 5) - Which box? Where does box start?
Step 1: Which BOX ROW GROUP? (0-2, 3-5, or 6-8?)
row = 4
row / 3 = 4 / 3 = 1 (integer division)
Meaning: Row 4 is in BOX ROW GROUP 1
Box row groups:
Group 0: rows 0,1,2 (rows 0-2)
Group 1: rows 3,4,5 (rows 3-5) โ Row 4 is here!
Group 2: rows 6,7,8 (rows 6-8)
Step 2: Where does BOX ROW GROUP 1 START?
Group 1 starts at row: 1 ร 3 = 3
Why multiply by 3?
Group 0 starts at: 0 ร 3 = 0 โ
Group 1 starts at: 1 ร 3 = 3 โ
Group 2 starts at: 2 ร 3 = 6 โ
So: boxRow = (4 / 3) ร 3 = 1 ร 3 = 3
Step 3: Which BOX COLUMN GROUP? (0-2, 3-5, or 6-8?)
col = 5
col / 3 = 5 / 3 = 1 (integer division)
Meaning: Col 5 is in BOX COL GROUP 1
Box col groups:
Group 0: cols 0,1,2 (cols 0-2)
Group 1: cols 3,4,5 (cols 3-5) โ Col 5 is here!
Group 2: cols 6,7,8 (cols 6-8)
Step 4: Where does BOX COL GROUP 1 START?
Group 1 starts at col: 1 ร 3 = 3
So: boxCol = (5 / 3) ร 3 = 1 ร 3 = 3
RESULT:
Cell (4, 5) belongs to box starting at (3, 3)
This is Box 4 (the center box)!
Visual:
0 1 2 | 3 4 5 | 6 7 8
0 . . . | . . . | . . .
1 . . . | . . . | . . .
2 . . . | . . . | . . .
--------+---------+--------
3 . . . |โฌ๏ธ . . | . . . โ boxRow = 3
4 . . . | . X . | . . . โ Cell (4,5)
5 . . . | . . . | . . .
--------+---------+--------
6 . . . | . . . | . . .
โฌ๏ธ
boxCol = 3
More Examples with Visuals
Example 2: Cell (0, 0) - Top-left corner
Step 1: row / 3 = 0 / 3 = 0
Step 2: boxRow = 0 ร 3 = 0
Step 3: col / 3 = 0 / 3 = 0
Step 4: boxCol = 0 ร 3 = 0
Box starts at: (0, 0) โ Top-left of Box 0 โ
0 1 2 | 3 4 5 | 6 7 8
0 โฌ๏ธ . . | . . . | . . .
1 . . . | . . . | . . .
2 . . . | . . . | . . .
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Example 3: Cell (8, 8) - Bottom-right corner
Step 1: row / 3 = 8 / 3 = 2
Step 2: boxRow = 2 ร 3 = 6
Step 3: col / 3 = 8 / 3 = 2
Step 4: boxCol = 2 ร 3 = 6
Box starts at: (6, 6) โ Top-left of Box 8 โ
0 1 2 | 3 4 5 | 6 7 8
6 . . . | . . . |โฌ๏ธ . .
7 . . . | . . . | . . .
8 . . . | . . . | . . X โ Cell (8,8)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Example 4: Cell (3, 7) - Middle-right area
Step 1: row / 3 = 3 / 3 = 1
Step 2: boxRow = 1 ร 3 = 3
Step 3: col / 3 = 7 / 3 = 2
Step 4: boxCol = 2 ร 3 = 6
Box starts at: (3, 6) โ Top-left of Box 5 โ
0 1 2 | 3 4 5 | 6 7 8
3 . . . | . . . |โฌ๏ธ X . โ Cell (3,7)
4 . . . | . . . | . . .
5 . . . | . . . | . . .
The Pattern - All Possible Starting Positions
There are only 9 possible box starting positions:
Box Row Groups ร Box Col Groups = 3 ร 3 = 9 boxes
โโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Box โ Starts at (boxRow, boxCol) โ
โโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Box 0 โ (0, 0) - top-left โ
โ Box 1 โ (0, 3) - top-center โ
โ Box 2 โ (0, 6) - top-right โ
โ Box 3 โ (3, 0) - middle-left โ
โ Box 4 โ (3, 3) - CENTER โ
โ Box 5 โ (3, 6) - middle-right โ
โ Box 6 โ (6, 0) - bottom-left โ
โ Box 7 โ (6, 3) - bottom-center โ
โ Box 8 โ (6, 6) - bottom-right โ
โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Notice the pattern:
Row starts: 0, 0, 0, 3, 3, 3, 6, 6, 6
Col starts: 0, 3, 6, 0, 3, 6, 0, 3, 6
Always multiples of 3!
How the Loop Works
Once we have box starting position (boxRow, boxCol):
for (int r = boxRow; r < boxRow + 3; r++) {
for (int c = boxCol; c < boxCol + 3; c++) {
// Check board[r][c]
}
}
This checks ALL 9 cells in the 3ร3 box!
Example: Box starting at (3, 3)
r goes from 3 to 5 (3, 4, 5)
c goes from 3 to 5 (3, 4, 5)
Checks cells:
(3,3) (3,4) (3,5)
(4,3) (4,4) (4,5)
(5,3) (5,4) (5,5)
All 9 cells in Box 4! โ
Visual:
0 1 2 | 3 4 5 | 6 7 8
3 . . . | X X X | . . . โ r=3
4 . . . | X X X | . . . โ r=4
5 . . . | X X X | . . . โ r=5
โ โ โ
c=3 c=4 c=5
Complete Mental Model
Think of it as:
"Which 3ร3 box am I in?" โ Find starting corner โ Check all 9 cells
Division by 3:
0,1,2 โ 0 (group 0)
3,4,5 โ 1 (group 1)
6,7,8 โ 2 (group 2)
Multiply by 3:
Group 0 โ starts at 0
Group 1 โ starts at 3
Group 2 โ starts at 6
Formula compactly expresses:
"Find which group (0,1,2), then find where that group starts (0,3,6)"
(row / 3) * 3 = rowGroup ร 3 = rowGroupStart
Alternative Way to Think About It
Another way to understand the formula:
boxRow = (row / 3) * 3
Can be rewritten as:
boxRow = row - (row % 3)
Examples:
row=0: 0 - (0%3) = 0 - 0 = 0 โ
row=1: 1 - (1%3) = 1 - 1 = 0 โ
row=2: 2 - (2%3) = 2 - 2 = 0 โ
row=3: 3 - (3%3) = 3 - 0 = 3 โ
row=4: 4 - (4%3) = 4 - 1 = 3 โ
row=5: 5 - (5%3) = 5 - 2 = 3 โ
row=6: 6 - (6%3) = 6 - 0 = 6 โ
row=7: 7 - (7%3) = 7 - 1 = 6 โ
row=8: 8 - (8%3) = 8 - 2 = 6 โ
This "rounds down to nearest multiple of 3"
Which gives us the box starting position!
๐ฏ Approach: Backtracking โญโญโญ
The Only Solution
Algorithm:
1. Find next empty cell (marked with '.')
2. If no empty cell โ Solved! Return true
3. For each digit 1-9:
a. Check if digit is valid (row, col, box)
b. If valid:
- Place digit
- Recursively solve rest
- If solved โ return true
- Else โ remove digit (backtrack)
4. If all digits 1-9 fail โ return false
Implementation
/**
* Backtracking solution for Sudoku
* Time: O(9^(nรn)) worst case, but pruning makes it much faster
* Space: O(nรn) - Recursion depth
*/
class Solution {
public void solveSudoku(char[][] board) {
solve(board);
}
private boolean solve(char[][] board) {
// Find next empty cell
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (board[row][col] == '.') {
// Try digits 1-9
for (char digit = '1'; digit <= '9'; digit++) {
if (isValid(board, row, col, digit)) {
// Place digit
board[row][col] = digit;
// Recursively solve rest
if (solve(board)) {
return true; // Solved!
}
// Backtrack - remove digit
board[row][col] = '.';
}
}
// All digits 1-9 failed
return false;
}
}
}
// No empty cell found - solved!
return true;
}
private boolean isValid(char[][] board, int row, int col, char digit) {
// Check row
for (int c = 0; c < 9; c++) {
if (board[row][c] == digit) {
return false;
}
}
// Check column
for (int r = 0; r < 9; r++) {
if (board[r][col] == digit) {
return false;
}
}
// Check 3ร3 box
int boxRow = (row / 3) * 3;
int boxCol = (col / 3) * 3;
for (int r = boxRow; r < boxRow + 3; r++) {
for (int c = boxCol; c < boxCol + 3; c++) {
if (board[r][c] == digit) {
return false;
}
}
}
return true;
}
public static void main(String[] args) {
Solution sol = new Solution();
char[][] board = {
{'5','3','.','.','7','.','.','.','.'},
{'6','.','.','1','9','5','.','.','.'},
{'.','9','8','.','.','.','.','6','.'},
{'8','.','.','.','6','.','.','.','3'},
{'4','.','.','8','.','3','.','.','1'},
{'7','.','.','.','2','.','.','.','6'},
{'.','6','.','.','.','.','2','8','.'},
{'.','.','.','4','1','9','.','.','5'},
{'.','.','.','.','8','.','.','7','9'}
};
sol.solveSudoku(board);
// Print solved board
for (char[] row : board) {
System.out.println(Arrays.toString(row));
}
}
}
โฐ Time: O(9^(nรn)) worst case, but typically much faster with pruning
๐พ Space: O(nรn) - Recursion depth (number of empty cells)
๐ Is Backtracking the Only Way?
Quick Answer: Backtracking is THE Standard Solution
For Sudoku Solver:
โ Backtracking: Standard, expected, works for all cases
โ Constraint Propagation: Advanced optimization
โ Brute Force: Too slow (9^81 possibilities!)
โ Dynamic Programming: Not applicable
Bottom Line: Backtracking is the standard solution!
Why Other Approaches Don't Apply
Brute Force (Try All Combinations):
โ COMPLETELY IMPRACTICAL
For 9ร9 Sudoku with ~50 empty cells:
9^50 = 5 ร 10^47 combinations!
Even at 1 billion checks per second:
Would take 10^30 years! ๐คฏ
Universe age: ~10^10 years
Backtracking prunes early โ Practical!
Dynamic Programming:
โ NOT APPLICABLE
Why DP doesn't work:
1. No optimal substructure
2. No overlapping subproblems
3. Constraints are global (entire board)
4. Each state depends on ALL previous placements
This is a CONSTRAINT SATISFACTION problem,
not an OPTIMIZATION problem.
Advanced: Constraint Propagation:
โ OPTIMIZATION (Not replacement!)
Techniques:
- Naked Singles: If cell has only one valid digit โ place it
- Hidden Singles: If digit has only one valid cell in row/col/box โ place it
- Pointing Pairs: Advanced eliminations
Used in combination with backtracking:
1. Apply constraint propagation first
2. Reduces search space
3. Then use backtracking for remaining cells
Still uses backtracking at core!
Mentioned only for completeness - not expected in interviews!
What Interviewers Expect
Standard Question:
Interviewer: "Solve this Sudoku"
Expected: Backtracking with validation
Follow-up Questions:
1. "How do you validate?"
Answer: "Check row, column, and 3ร3 box for duplicate"
2. "Can you optimize?"
Answer: "Yes - instead of finding empty cells during recursion,
precompute list of empty cells. Saves time."
3. "What's the time complexity?"
Answer: "Worst case O(9^m) where m = empty cells.
But pruning makes it much faster in practice."
4. "Is there a better approach?"
Answer: "For interviews, backtracking is standard.
Advanced solvers use constraint propagation,
but that's beyond interview scope."
Interview Strategy
STEP 1: Recognize it's backtracking
"This is a constraint satisfaction problem.
I'll use backtracking to try values and backtrack when stuck."
STEP 2: Explain validation
"For each empty cell, I'll try digits 1-9.
For each digit, I'll validate:
- Row doesn't have it
- Column doesn't have it
- 3ร3 box doesn't have it"
STEP 3: Explain backtracking
"If valid, place digit and recurse.
If recursion succeeds, we're done.
If it fails, remove digit and try next."
STEP 4: Code it up
- solve() function with backtracking
- isValid() function for constraint checking
โ ๏ธ Common Mistakes
Mistake 1: Not backtracking (not removing digit)
// โ WRONG - Digit stays placed even when path fails!
if (isValid(board, row, col, digit)) {
board[row][col] = digit;
if (solve(board)) return true;
// Forgot to remove!
}
// โ CORRECT - Remove digit after failed attempt
if (isValid(board, row, col, digit)) {
board[row][col] = digit;
if (solve(board)) return true;
board[row][col] = '.'; // Backtrack!
}
Mistake 2: Wrong box calculation
// โ WRONG - Incorrect box boundaries
int boxRow = row / 3;
int boxCol = col / 3;
for (int r = boxRow; r < boxRow + 3; r++) {
// This checks wrong cells!
}
// โ CORRECT - Multiply by 3 to get starting position
int boxRow = (row / 3) * 3;
int boxCol = (col / 3) * 3;
for (int r = boxRow; r < boxRow + 3; r++) {
for (int c = boxCol; c < boxCol + 3; c++) {
// Now checking correct 3ร3 box
}
}
Mistake 3: Modifying board in isValid
// โ WRONG - Validation should not modify board!
private boolean isValid(char[][] board, int row, int col, char digit) {
board[row][col] = digit; // Modifying!
// Check...
board[row][col] = '.';
return valid;
}
// โ CORRECT - Only check, don't modify
private boolean isValid(char[][] board, int row, int col, char digit) {
// Check row, col, box
// Don't modify board!
return valid;
}
Mistake 4: Not returning true when solved
// โ WRONG - Keeps searching even after solution found!
if (solve(board)) {
// Continue to next iteration!
}
// โ CORRECT - Return immediately when solved
if (solve(board)) {
return true; // Solved! Stop searching!
}
Mistake 5: Checking board[row][col] in validation
// โ WRONG - Checks cell being filled!
private boolean isValid(char[][] board, int row, int col, char digit) {
for (int c = 0; c < 9; c++) {
if (board[row][c] == digit) { // Checks (row, col) too!
return false;
}
}
}
// โ CORRECT - Skip the cell being filled
private boolean isValid(char[][] board, int row, int col, char digit) {
for (int c = 0; c < 9; c++) {
if (c != col && board[row][c] == digit) { // Skip (row, col)
return false;
}
}
}
// OR: Check before placing (like in our main solution)
๐ฏ Pattern Recognition
Problem Type: Constraint Satisfaction
Core Pattern: Backtracking with Validation
When to Apply:
โ Must satisfy multiple constraints
โ Need to fill cells/slots with values
โ Constraints are interdependent
โ Guaranteed unique solution
Recognition Keywords:
- "solve a puzzle"
- "satisfy rules/constraints"
- "valid placement"
- "fill the grid"
Similar Problems:
- N-Queens (LC 51) - Place queens without conflicts
- Valid Sudoku (LC 36) - Just validate, don't solve
- Sudoku Solver variants - Different grid sizes
Key Components:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Backtracking: Try values, undo if fail โ
โ Validation: Check row, col, box โ
โ Base case: No empty cells โ solved! โ
โ Try all: Loop through 1-9 โ
โ Prune: Skip invalid early โ
โ Time: O(9^m), Space: O(m) (m=empty cells) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ง Interview Strategy
Step 1: "This is backtracking with constraint checking"
Step 2: "Find empty cell, try 1-9, validate each"
Step 3: "If valid, place and recurse. If stuck, backtrack"
Key Points to Mention:
- Three constraints: row, column, 3ร3 box
- Try each digit 1-9 for empty cell
- Validate before placing
- Backtrack if path fails
- Modify board in-place
Walk Through:
"For this board:
Find first empty at (0,2)
Try 1: Check row 0, col 2, box 0 โ Valid? Try it
Recurse to next empty...
If later fails โ Come back, remove 1
Try 2: Check constraints โ Valid? Try it
Recurse...
Continue until board complete or backtrack when stuck"
Validation Explanation:
"For placing digit at (row, col):
ROW: Check if digit in board[row][0..8]
COL: Check if digit in board[0..8][col]
BOX: Calculate box start: (row/3)*3, (col/3)*3
Check 3ร3 region from box start
If all three pass โ Valid!"
Complexity:
"Time: O(9^m) where m = empty cells
Each cell: try 9 digits
m cells: 9^m possibilities
But pruning makes it much faster!
Space: O(m) recursion depth
Each level: one empty cell
Depth = number of empty cells"
Optimizations (if asked):
"1. Precompute empty cells list
2. Try digits with fewest conflicts first
3. Use bitsets for faster validation
But basic backtracking is sufficient!"
๐ Quick Revision Notes
๐ฏ Core Concept:
Sudoku Solver: Use backtracking to fill empty cells. For each empty cell, try digits 1-9. For each digit, validate (check row, col, 3ร3 box). If valid, place digit and recurse. If recursion fails, backtrack (remove digit, try next). Continue until board complete. Box calculation: (row/3)*3, (col/3)*3.
โก Quick Implementation:
public class Solution {
public void solveSudoku(char[][] a) {
backtracking(a);
}
private boolean backtracking(char[][] a) {
// step 1: start looping through each cell looking for empty cell.
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
// step 2: empty cell found
if (a[i][j] == '.') {
// step 3: try each digit for that empty cell if it fits
for (char k = '1'; k <= '9'; k++) {
// step 4: can we place 'c' at (i, j)?
if (isValid(a, i, j, k)) {
// step 5: if we can place 'c' at (i, j), update the character
// in the board and solve for remaining empty cells
a[i][j] = k;
// step 6: solve for remaining.
// if solved for remaining, return true from here only
// and no need to try anything else.
if (backtracking(a)) {
return true;
}
// step 7: if above try failed, backtracking with new digit
a[i][j] = '.';
}
}
// step 8: you tried all digits and nothing worked for this cell
return false;
}
}
}
// step 9: there are no more empty cells.
// Sudoku is successfully solved, so returns true
return true;
}
private boolean isValid(char[][] a, int row, int col, char ch) {
// step 10: check all chars in 'row'
for (int c = 0; c < a[0].length; c++) {
if (a[row][c] == ch) {
return false;
}
}
// step 11: check all chars in 'col'
for (int r = 0; r < a.length; r++) {
if (a[r][col] == ch) {
return false;
}
}
// step 12: check all chars in the 'box'
int boxRow = (row / 3) * 3;
int boxCol = (col / 3) * 3;
for (int r = boxRow; r < boxRow + 3; r++) {
for (int c = boxCol; c < boxCol + 3; c++) {
if (a[r][c] == ch) {
return false;
}
}
}
return true;
}
public static void main(String[] args) {
Solution s = new Solution();
char[][] board = {
{ '5', '3', '.', '.', '7', '.', '.', '.', '.' },
{ '6', '.', '.', '1', '9', '5', '.', '.', '.' },
{ '.', '9', '8', '.', '.', '.', '.', '6', '.' },
{ '8', '.', '.', '.', '6', '.', '.', '.', '3' },
{ '4', '.', '.', '8', '.', '3', '.', '.', '1' },
{ '7', '.', '.', '.', '2', '.', '.', '.', '6' },
{ '.', '6', '.', '.', '.', '.', '2', '8', '.' },
{ '.', '.', '.', '4', '1', '9', '.', '.', '5' },
{ '.', '.', '.', '.', '8', '.', '.', '7', '9' }
};
s.solveSudoku(board);
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
}
}
๐ Key Insights:
- Pattern: Constraint Satisfaction with Backtracking
- 3 Constraints: Row, Column, 3ร3 Box (all must be checked!)
- Try 1-9: For each empty cell
- Validate First: Before placing digit
- Backtrack: MUST remove digit if path fails
- Box Calculation:
(row/3)*3and(col/3)*3for start - Time: O(9^m) where m = empty cells, Space: O(m) โ
๐ช Memory Aid:
"Find empty, try 1-9, check row-col-box, backtrack if stuck!"
"Box start: (row/3)3, (col/3)3!" โจ
โ ๏ธ Critical Points:
Box Calculation - THE INTUITIVE EXPLANATION:
Goal: Given cell (row, col), find top-left corner of its 3ร3 box
Think in terms of GROUPS:
Rows divided into 3 groups:
Group 0: rows 0,1,2 (starts at row 0)
Group 1: rows 3,4,5 (starts at row 3)
Group 2: rows 6,7,8 (starts at row 6)
Cols divided into 3 groups:
Group 0: cols 0,1,2 (starts at col 0)
Group 1: cols 3,4,5 (starts at col 3)
Group 2: cols 6,7,8 (starts at col 6)
Formula: boxRow = (row / 3) * 3
Step-by-step for cell (4, 5):
ROW:
row / 3 = 4 / 3 = 1 โ Which group? Group 1
1 * 3 = 3 โ Group 1 starts at row 3
boxRow = 3 โ
COL:
col / 3 = 5 / 3 = 1 โ Which group? Group 1
1 * 3 = 3 โ Group 1 starts at col 3
boxCol = 3 โ
Box starts at (3, 3) โ
Visual for (4, 5):
0 1 2 | 3 4 5 | 6 7 8
3 . . . |โฌ๏ธ . . | . . . โ boxRow = 3
4 . . . | . X . | . . . โ row=4, col=5
5 . . . | . . . | . . .
โฌ๏ธ
boxCol = 3
The pattern:
Division by 3 โ Which group (0, 1, or 2)?
Multiply by 3 โ Where does that group start (0, 3, or 6)?
All possible box starts: (0,0), (0,3), (0,6),
(3,0), (3,3), (3,6),
(6,0), (6,3), (6,6)
Always multiples of 3!
Alternative formula (same result):
boxRow = row - (row % 3)
"Round down to nearest multiple of 3"
Backtracking (MUST DO!):
board[row][col] = digit;
if (solve(board)) return true;
board[row][col] = '.'; โ CRITICAL!
Without this:
Digit stays even when path fails! โ
Return Values:
- return true: Board solved OR path succeeds
- return false: No valid digit for this cell
- No empty cell found: Board complete โ true
๐งช Edge Cases
Case 1: Almost solved (1 cell empty)
Only one cell needs filling
Quick solution
Case 2: Many empty cells
Harder, more backtracking needed
Still solvable with backtracking
Case 3: Requires deep backtracking
Early choices lead to dead ends
Must backtrack many levels
Algorithm handles it correctly
All handled by backtracking! โ
๐ Complexity Analysis
Time Complexity: O(9^m)
Where m = number of empty cells
Why?
Each empty cell: try up to 9 digits
m cells: 9 ร 9 ร 9 ร ... (m times) = 9^m
Worst case: m = 81 (all empty)
9^81 = huge number!
But pruning (validation) eliminates most paths early!
Actual runtime much better than worst case.
Example:
m = 50 empty cells
Worst case: 9^50 = 5 ร 10^47
With pruning: ~10^6 - 10^9 operations (practical!)
Space Complexity: O(m)
Recursion stack depth:
Maximum depth = m (number of empty cells)
Each recursive call: O(1) space
Total: O(m)
Board modification: In-place (O(1))
Total: O(m) auxiliary space
๐ Related Problems
Same Core Pattern: - N-Queens (LC 51) - Backtracking with constraints - Valid Sudoku (LC 36) - Just validation (no solving) - Sudoku Solver variants - Different grid sizes
Similar Backtracking: - Word Search (LC 79) - Path finding on grid - Combination Sum (LC 39) - Try values with constraints - Permutations (LC 46) - Generate all arrangements
Happy practicing! ๐ฏ
Note: This is the classic constraint satisfaction problem! Master this and you understand: (1) backtracking with multiple constraints, (2) in-place modification and restoration, (3) pruning invalid paths early, (4) box/grid indexing. Very impressive problem for FAANG interviews - shows deep understanding of backtracking! The key trick is the box calculation: (row/3)*3 and (col/3)*3! ๐ชโจ