Valid Sudoku
We use boolean arrays as little checklists to track numbers in each row, column, and box. This follows a validation pattern—as we scan the board, we just mark numbers as “seen” so we can catch duplicates right away.
- Problem
- Solution
- Step-by-Step Breakdown
- Step 5: Check for Duplicates
- Step 6: Mark the Digit as Seen
- Step 7: Return True
- Dry Run Example
- Whiteboard Visual Flow
- Big O Analysis (Beginner-Friendly)
- Key Takeaways
Problem
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
- Each row must contain digits 1–9 without repetition.
- Each column must contain digits 1–9 without repetition.
- Each of the 9 sub-boxes (3x3 sections) must contain digits 1–9 without repetition.
Solution
Here’s the complete solution in Java:
class Solution {
public boolean isValidSudoku(char[][] board) {
// Step 1 : initialize boolean matrices for rows, columns, and sub-boxes
boolean[][] rows = new boolean[9][9];
boolean[][] columns = new boolean[9][9];
boolean[][] subBoxes = new boolean[9][9];
// Step 2 : iterate over each cell in the 9x9 board
for(int row=0;row<board.length; row++) {
for(int column=0;board.length; column++) {
if(board[row][column] != '.') {
int num = board[row][column] - '1';
// Step 3 : calculate sub-box index
int boxIndex = (row/3)*3 + (column/3);
// Step 4 : check for duplicates
if(rows[row][num] || columns[column][num] || subBoxes[boxIndex][num]) {
return false;
}
// Step 5 : mark the digit as seen
rows[row][num] = true;
columns[column][num] = true;
subBoxes[boxIndex][num] = true;
}
}
}
return true;
}
}
Step-by-Step Breakdown
Step 1: Initialize Tracking Structures
boolean[][] rows = new boolean[9][9];
boolean[][] columns = new boolean[9][9];
boolean[][] subBoxes = new boolean[9][9];
• We create three 9x9 boolean matrices:
• rows[row][num] → has number num been seen in row i?
• columns[column][num] → has number num been seen in column j?
• subBoxes[boxIndex][num] → has number num been seen in 3x3 sub-box boxIndex?
Step 2: Iterate Over the Grid
for(int row=0;row<board.length;row++) {
for(int column=0;column<board.length;column++) {
• Loop through each cell in the 9x9 board.
• If the cell is empty (.), skip it.
if(board[row][column] != '.') {
int num = board[row][column] - '1';
Step 3: Convert Digit into Index
int num = board[row][column] - '1';
• Characters '1' to '9' are converted to indices 0 to 8.
• Example: if board[row][column] = '5', then num = 4.
Whats going on here?
1. board[row][column] → gives us a character like '1', '5', or '9'.
• Remember, the Sudoku board is a char[][], not an int[][].
2. Characters in Java are stored as ASCII (or Unicode) codes.
• '1' has a code of 49.
• '2' has a code of 50.
• ... up to '9' with code 57.
Why do this?
Because our boolean arrays are indexed from 0 to 8, not 1 to 9. • Index 0 means “digit 1 is present.” • Index 1 means “digit 2 is present.” • … • Index 8 means “digit 9 is present.”
So this line basically converts the character digit into the correct array index.
Step 4: Calculate Sub-Box Index
int boxIndex = (row/3)*3 + (column/3);
• The board is divided into 9 sub-boxes (3x3 each).
• Formula assigns each cell to its corresponding sub-box.
Visual: Sub-box indexing
0 1 2
+-------+-------+-------+
| 0 | 1 | 2 | 0
+-------+-------+-------+
| 3 | 4 | 5 | 1
+-------+-------+-------+
| 6 | 7 | 8 | 2
+-------+-------+-------+
Example: Cell (4,5) → (row/3)3 + (column/3) = (4/3)3 + (5/3) = 1*3 + 1 = 4 → Sub-box 4.
Step 5: Check for Duplicates
if(rows[row][num] || columns[column][num] || subBoxes[boxIndex][num]) {
return false;
}
• If the digit already exists in:
• The same row, OR
• The same column, OR
• The same sub-box → ❌ Invalid Sudoku.
Step 6: Mark the Digit as Seen
rows[row][num] = true;
columns[column][num] = true;
subBoxes[boxIndex][num] = true;
• Otherwise, mark this number as seen for row, column, and box.
Step 7: Return True
return true;
• If no duplicates are found after scanning the entire board → ✅ Valid Sudoku.
Dry Run Example
Board Input (simplified):
[
['5','3','.','.','7','.','.','.','.'],
['6','.','.','1','9','5','.','.','.'],
['.','9','8','.','.','.','.','6','.'],
...
]
Tracking Flow:
1. (0,0) → ‘5’ → row[0][4] = true, col[0][4] = true, subBox[0][4] = true
2. (0,1) → ‘3’ → row[0][2] = true, col[1][2] = true, subBox[0][2] = true
3. (1,3) → ‘1’ → row[1][0] = true, col[3][0] = true, subBox[1][0] = true
...
If a duplicate is found at any point → return false.
Whiteboard Visual Flow
Cell → Convert to num → Find sub-box → Check rows, cols, sub-box
↓ ↓ ↓ ↓
[5] → 4 → subBox 0 → not seen → mark as true
Big O Analysis (Beginner-Friendly)
Time Complexity
- The algorithm scans each cell once → 9x9 = 81 cells → O(1).
- Generalized: O(n²) for an n x n Sudoku grid.
Space Complexity
- Three 9x9 boolean arrays → O(1) fixed size (does not grow with input).
✅ Result:
- Time: O(1) (since Sudoku size is fixed).
- Space: O(1).
Why is it O(n²)
Sudoku is a grid problem. In the standard puzzle: • n = 9 (a 9x9 board). • That means there are n × n = 81 cells to check.
Our algorithm looks at every single cell once:
for (int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
// work = constant time
}
}
• Two nested loops → n × n iterations.
• Each step does constant-time work (array lookups and boolean updates).
So:
Time Complexity = O(n * n) = O(n²)
The algorithm checks every cell once. If we define n as the grid size (rows or columns), it’s O(n²). If we define n as the total number of cells, it’s O(n). For a standard 9x9 Sudoku, both simply mean it scales linearly with the number of cells.
Sudoku Board: 9 x 9 = 81 cells
Interpretation 1: n = grid size (rows/columns)
n = 9
Total cells = n × n = 9 × 9 = 81
Time complexity = O(n²)
➡️ Each step = “look at 1 cell”
➡️ Total = 81 steps ≈ O(n²)
Interpretation 2: n = total number of cells
n = 81
Time complexity = O(n)
➡️ Each step = “look at 1 cell”
➡️ Total = 81 steps ≈ O(n)
Key Takeaways
- Use boolean matrices to track seen numbers across rows, columns, and sub-boxes.
- The formula (i/3)*3 + (j/3) maps a cell to its sub-box.
- Efficient validation → scans board once, constant time complexity.
- This approach teaches the importance of state tracking in multi-dimensional problems.