Master the art of validating Sudoku boards efficiently using hash sets and fixed-size arrays with O(1) complexity.
Youâve probably played Sudoku beforeâmaybe on a long flight or in the back of a newspaper. Itâs that number puzzle where you fill a 9Ă9 grid following some pretty strict rules. But hereâs the thing: in the Valid Sudoku problem (LeetCode #36), weâre not actually solving the puzzle. Weâre just checking if someone hasnât already broken the rules.
Think of yourself as the referee, not the player. Youâre given a partially filled board, and your job is to verify that whatâs there so far doesnât violate any Sudoku rules. This makes for a great exercise in matrix traversal and hashing, and itâll really test whether you can map 2D coordinates to specific constraints efficiently.
A Sudoku board is valid when:
1-9 without any repeats.1-9 without any repeats.3x3 sub-boxes contains the digits 1-9 without any repeats.Hereâs what trips people up: The board doesnât need to be complete, and it doesnât even need to be solvable. We only care that the existing numbers donât contradict each other. Empty cells (shown as '.') get a free passâwe ignore them completely.
Real-World Analogy: Imagine youâre a building inspector with three checklists. You walk through the building (the board) once. For every room (cell) you enter, you check:
Letâs look at how a Sudoku board is actually structured before we get into the code.
Click "Start Validation" to begin checking the Sudoku board
Checking rows and columns? Easy. You just iterate through indices [row][0...8] or [0...8][col].
But the 3x3 sub-boxes? Thatâs where it gets interesting.
The board splits into nine 3x3 sub-boxes arranged in a 3x3 grid. We need a way to mathematically map any cell (row, col) to a specific box index from 0 to 8. And we need to do it fast.
Key Formula: The box index k for a cell at (r, c) is calculated as: k = (r / 3) * 3 + (c / 3)
Letâs break down the math (using integer division):
r / 3: Which block row is this cell in? (0, 1, or 2)c / 3: Which block column is this cell in? (0, 1, or 2)Say we have a cell at (4, 7):
4 // 3 = 1 (Weâre in the middle block-row)7 // 3 = 2 (Weâre in the rightmost block-col)index = 1 * 3 + 2 = 5 (Thatâs the 6th box, using 0-based indexing)Pretty neat, right?
Try playing with the board below. Youâll see how conflicts get detected immediately based on those three rules we talked about.
Instructions: Click a cell to select it, then use the number pad or keyboard (1-9) to enter values. Press Backspace/Delete or click "Clear Cell" to remove a value. Errors are highlighted in real-time.
Hereâs the beautiful partâwe can validate the entire board in a single pass through all 81 cells. We just maintain three sets of âseenâ records:
(i, j) from (0,0) to (8,8).'.', skip itânothing to check.num:num already in rows[i]?num already in cols[j]?num already in boxes[box_index]?false. We found a violation.num to all three records.true.Click "Start Algorithm" to begin the validation process
No numbers being tracked
Time Complexity: O(1) - Since the board is always 9Ă9, we check exactly 27 units (9 rows + 9 columns + 9 boxes)
Space Complexity: O(1) - We use a HashSet of at most 9 elements for each unit
Algorithm Steps:
You can implement this using Hash Sets (more flexible but slightly slower) or Fixed-Size Arrays (faster and more memory-efficient). The solution below uses Fixed-Size Boolean Arrays, which is the standard approach for this problem since weâre always dealing with digits 1-9.
class Solution {
public boolean isValidSudoku(char[][] board) {
// Use boolean arrays to track seen numbers
// Dimensions: [9 indices][9 possible numbers]
boolean[][] rows = new boolean[9][9];
boolean[][] cols = new boolean[9][9];
boolean[][] boxes = new boolean[9][9];
for (int r = 0; r < 9; r++) {
for (int c = 0; c < 9; c++) {
// Skip empty cells
if (board[r][c] == '.') {
continue;
}
// Convert char '1'-'9' to integer index 0-8
int num = board[r][c] - '1';
// Calculate sub-box index
int boxIndex = (r / 3) * 3 + (c / 3);
// Check for duplicates
if (rows[r][num] || cols[c][num] || boxes[boxIndex][num]) {
return false; // Violation found
}
// Mark number as seen
rows[r][num] = true;
cols[c][num] = true;
boxes[boxIndex][num] = true;
}
}
return true;
}
} Time Complexity: O(1) - Specifically O(81).
Since the Sudoku board is always 9x9, weâre always doing a constant number of operations. We visit 81 cells exactly once. (If this were generalized to an board, weâd be looking at since weâd visit every cell once.)
Space Complexity:
â ď¸ Pitfall: Confusing Validity with Solvability.
This is the most common mistake. People think they need to use backtracking to check if the board can be solved. But thatâs not what weâre doing here. This problem only asks if the current numbers are valid. A board with just ['1', '2', '3', ...] followed by empty cells is perfectly valid, even if it might be impossible to complete later.
Other Mistakes to Watch Out For:
'1'-'9', but array indices are 0-8. Donât forget to subtract '1' (or 1) when converting.% instead of / for the box calculation. Remember, (r % 3) gives you the position inside a box, not which box youâre in.'5' to the integer 5 (or index 4) correctly.Want to squeeze out every last bit of performance? In C++ or Java, you can replace the boolean arrays with integers using bitmasks.
k is present: (row[i] >> k) & 1.k as seen: row[i] |= (1 << k).This cuts down on the space complexity constant factors significantly (though the Big-O stays the same). Itâs a nice trick to have in your back pocket.
Valid Sudoku is one of those foundational constraint satisfaction problems thatâs worth understanding well. Once youâve got the grid traversal down and youâre comfortable with that sub-box indexing formula (row / 3) * 3 + (col / 3), youâll be ready for more complex matrix problemsâincluding the full Sudoku Solver algorithm.
The key takeaway? Iterate once, check three constraints, and use O(1) lookups. Keep it simple, and youâll be fine.