You are given a 9 x 9 Sudoku board board. A Sudoku board is valid if the following rules are followed:
1-9 without duplicates.1-9 without duplicates.3 x 3 sub-boxes of the grid must contain the digits 1-9 without duplicates.Return true if the Sudoku board is valid, otherwise return false
Note: A board does not need to be full or be solvable to be valid.
Example 1:
Input: board =
[["1","2",".",".","3",".",".",".","."],
["4",".",".","5",".",".",".",".","."],
[".","9","8",".",".",".",".",".","3"],
["5",".",".",".","6",".",".",".","4"],
[".",".",".","8",".","3",".",".","5"],
["7",".",".",".","2",".",".",".","6"],
[".",".",".",".",".",".","2",".","."],
[".",".",".","4","1","9",".",".","8"],
[".",".",".",".","8",".",".","7","9"]]
Output: trueExample 2:
Input: board =
[["1","2",".",".","3",".",".",".","."],
["4",".",".","5",".",".",".",".","."],
[".","9","1",".",".",".",".",".","3"],
["5",".",".",".","6",".",".",".","4"],
[".",".",".","8",".","3",".",".","5"],
["7",".",".",".","2",".",".",".","6"],
[".",".",".",".",".",".","2",".","."],
[".",".",".","4","1","9",".",".","8"],
[".",".",".",".","8",".",".","7","9"]]
Output: falseExplanation: There are two 1's in the top-left 3x3 sub-box.
Constraints:
board.length == 9board[i].length == 9board[i][j] is a digit 1-9 or '.'.
You should aim for a solution as good or better than O(n^2) time and O(n^2) space, where n is the number of rows in the square grid.
Which data structure would you prefer to use for checking duplicates?
You can use a hash set for every row and column to check duplicates. But how can you efficiently check for the squares?
We can find the index of each square by the equation (row / 3) * 3 + (col / 3). Then we use hash set for O(1) lookups while inserting the number into its row, column and square it belongs to. We use separate hash maps for rows, columns, and squares.
Before attempting this problem, you should be comfortable with:
A valid Sudoku board must follow three rules:
1–9 at most once.1–9 at most once.1–9 at most once.We can directly check all these conditions one by one.
For every row, every column, and every 3×3 box, we keep a set of seen digits and make sure no number appears twice.
If we ever find a duplicate in any of these three checks, the board is invalid.
Check all rows:
row from 0 to 8:seen.i from 0 to 8:".".seen, return false.seen.Check all columns:
col from 0 to 8:seen.i from 0 to 8:".".seen, return false.seen.Check all 3×3 boxes:
0 to 8.square:seen.i in 0..2 and j in 0..2:row = (square // 3) * 3 + icol = (square % 3) * 3 + j".".seen, return false.seen.If all rows, columns, and 3×3 boxes pass these checks without duplicates, return true.
Input Sudoku Board:
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 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝PHASE 1: Check Rows
Checking Row 0:
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║[5]│ 3 │ . ║ . │ 7 │ . ║ . │ . │ . ║ ← Checking this row
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
↑
Current cellStep 1: Check cell (0, 0) = '5'
seen = { }
'5' not in seen → add it
seen = { 5 }Step 2: Check cell (0, 1) = '3'
seen = { 5 }
'3' not in seen → add it
seen = { 5, 3 }Step 3: Check cell (0, 2) = '.' → skip (empty cell)
Step 4: Check cell (0, 3) = '.' → skip (empty cell)
Step 5: Check cell (0, 4) = '7'
seen = { 5, 3 }
'7' not in seen → add it
seen = { 5, 3, 7 }... continue for remaining cells in row 0
Result: Row 0 is valid (no duplicates found)
PHASE 2: Check Columns
Checking Column 0:
0
╔═══╗
0 ║[5]║ ← Current cell
╟───╢
1 ║ 6 ║
╟───╢
2 ║ . ║
╠═══╣
3 ║ 8 ║
╟───╢
4 ║ 4 ║
╟───╢
5 ║ 7 ║
╠═══╣
6 ║ . ║
╟───╢
7 ║ . ║
╟───╢
8 ║ . ║
╚═══╝Step 1: Check cell (0, 0) = '5'
seen = { }
'5' not in seen → add it
seen = { 5 }Step 2: Check cell (1, 0) = '6'
seen = { 5 }
'6' not in seen → add it
seen = { 5, 6 }Step 3: Check cell (2, 0) = '.' → skip (empty cell)
Step 4: Check cell (3, 0) = '8'
seen = { 5, 6 }
'8' not in seen → add it
seen = { 5, 6, 8 }... continue for remaining cells in column 0
Result: Column 0 is valid (no duplicates found)
PHASE 3: Check 3x3 Boxes
Checking Box 0 (top-left, rows 0-2, cols 0-2):
0 1 2
╔═══╤═══╤═══╗
0 ║[5]│ 3 │ . ║ ← Start here
╟───┼───┼───╢
1 ║ 6 │ . │ . ║
╟───┼───┼───╢
2 ║ . │ 9 │ 8 ║
╚═══╧═══╧═══╝
Traversal order: (0,0) → (0,1) → (0,2) → (1,0) → (1,1) → (1,2) → (2,0) → (2,1) → (2,2)Step 1: Check cell (0, 0) = '5'
seen = { }
'5' not in seen → add it
seen = { 5 }Step 2: Check cell (0, 1) = '3'
seen = { 5 }
'3' not in seen → add it
seen = { 5, 3 }Step 3: Check cell (0, 2) = '.' → skip
Step 4: Check cell (1, 0) = '6'
seen = { 5, 3 }
'6' not in seen → add it
seen = { 5, 3, 6 }Step 5: Check cell (1, 1) = '.' → skip
Step 6: Check cell (1, 2) = '.' → skip
Step 7: Check cell (2, 0) = '.' → skip
Step 8: Check cell (2, 1) = '9'
seen = { 5, 3, 6 }
'9' not in seen → add it
seen = { 5, 3, 6, 9 }Step 9: Check cell (2, 2) = '8'
seen = { 5, 3, 6, 9 }
'8' not in seen → add it
seen = { 5, 3, 6, 9, 8 }Result: Box 0 is valid (no duplicates found)
After checking all 9 rows, 9 columns, and 9 boxes with no duplicates found, return True.
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
for row in range(9):
seen = set()
for i in range(9):
if board[row][i] == ".":
continue
if board[row][i] in seen:
return False
seen.add(board[row][i])
for col in range(9):
seen = set()
for i in range(9):
if board[i][col] == ".":
continue
if board[i][col] in seen:
return False
seen.add(board[i][col])
for square in range(9):
seen = set()
for i in range(3):
for j in range(3):
row = (square//3) * 3 + i
col = (square % 3) * 3 + j
if board[row][col] == ".":
continue
if board[row][col] in seen:
return False
seen.add(board[row][col])
return TrueInstead of checking rows, columns, and 3×3 boxes separately, we can validate the entire Sudoku board in one single pass.
For each cell, we check whether the digit has already appeared in:
We track these using three hash sets:
rows[r] keeps digits seen in row rcols[c] keeps digits seen in column csquares[(r // 3, c // 3)] keeps digits in the 3×3 boxIf a digit appears again in any of these places, the board is invalid.
Create three hash maps of sets:
rows to track digits in each rowcols to track digits in each columnsquares to track digits in each 3×3 sub-box, keyed by (r // 3, c // 3)Loop through every cell in the board:
".".val be the digit in the cell.val is already in:rows[r] → duplicate in the rowcols[c] → duplicate in the columnsquares[(r // 3, c // 3)] → duplicate in the 3×3 boxfalse.Otherwise, add the digit to all three sets:
rows[r]cols[c]squares[(r // 3, c // 3)]If the whole board is scanned without detecting duplicates, return true.
Input Sudoku Board:
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 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
Box Index Map (for reference):
╔═══════════╦═══════════╦═══════════╗
║ Box 0 ║ Box 1 ║ Box 2 ║
║ (0//3, ║ (0//3, ║ (0//3, ║
║ 0//3) ║ 1//3) ║ 2//3) ║
╠═══════════╬═══════════╬═══════════╣
║ Box 3 ║ Box 4 ║ Box 5 ║
╠═══════════╬═══════════╬═══════════╣
║ Box 6 ║ Box 7 ║ Box 8 ║
╚═══════════╩═══════════╩═══════════╝Data Structures:
rows[r] = set of digits seen in row rcols[c] = set of digits seen in column csquares[(r//3, c//3)] = set of digits seen in that 3x3 boxONE-PASS WALKTHROUGH
Step 1: Process cell (0, 0) = '5'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║[5]│ 3 │ . ║ . │ 7 │ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ Box index: (0//3, 0//3) = (0, 0)
Check for duplicates:
'5' in rows[0]? No (empty)
'5' in cols[0]? No (empty)
'5' in squares[(0,0)]? No (empty)
Update all three sets:
rows[0] = { 5 }
cols[0] = { 5 }
squares[(0,0)] = { 5 }
No duplicates found → ContinueStep 2: Process cell (0, 1) = '3'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │[3]│ . ║ . │ 7 │ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ Box index: (0//3, 1//3) = (0, 0)
Check for duplicates:
'3' in rows[0]? No (rows[0] = {5})
'3' in cols[1]? No (empty)
'3' in squares[(0,0)]? No (squares[(0,0)] = {5})
Update all three sets:
rows[0] = { 5, 3 }
cols[1] = { 3 }
squares[(0,0)] = { 5, 3 }
No duplicates found → ContinueStep 3: Process cell (0, 2) = '.' → skip (empty cell)
Step 4: Process cell (0, 3) = '.' → skip (empty cell)
Step 5: Process cell (0, 4) = '7'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │ 3 │ . ║ . │[7]│ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ Box index: (0//3, 4//3) = (0, 1) ← Different box!
Check for duplicates:
'7' in rows[0]? No (rows[0] = {5, 3})
'7' in cols[4]? No (empty)
'7' in squares[(0,1)]? No (empty)
Update all three sets:
rows[0] = { 5, 3, 7 }
cols[4] = { 7 }
squares[(0,1)] = { 7 }
No duplicates found → Continue... (continue scanning row 0, then move to row 1)
Step 10: Process cell (1, 0) = '6'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │ 3 │ . ║ . │ 7 │ . ║ . │ . │ . ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
1 ║[6]│ . │ . ║ 1 │ 9 │ 5 ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ Box index: (1//3, 0//3) = (0, 0) ← Same box as cell (0,0)
Check for duplicates:
'6' in rows[1]? No (empty)
'6' in cols[0]? No (cols[0] = {5})
'6' in squares[(0,0)]? No (squares[(0,0)] = {5, 3})
Update all three sets:
rows[1] = { 6 }
cols[0] = { 5, 6 }
squares[(0,0)] = { 5, 3, 6 }
No duplicates found → ContinueSTATE AFTER PROCESSING FIRST TWO ROWS
Row Sets:
rows[0] = { 5, 3, 7 }
rows[1] = { 6, 1, 9, 5 }
Column Sets:
cols[0] = { 5, 6 }
cols[1] = { 3 }
cols[3] = { 1 }
cols[4] = { 7, 9 }
cols[5] = { 5 }
Box Sets:
squares[(0,0)] = { 5, 3, 6 } (top-left box)
squares[(0,1)] = { 7, 1, 9, 5 } (top-middle box)Continue processing all cells. If no duplicate is found in any row, column, or box, return True.
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
cols = defaultdict(set)
rows = defaultdict(set)
squares = defaultdict(set)
for r in range(9):
for c in range(9):
if board[r][c] == ".":
continue
if ( board[r][c] in rows[r]
or board[r][c] in cols[c]
or board[r][c] in squares[(r // 3, c // 3)]):
return False
cols[c].add(board[r][c])
rows[r].add(board[r][c])
squares[(r // 3, c // 3)].add(board[r][c])
return TrueEvery digit from 1 to 9 can be represented using a single bit in an integer.
For example, digit 1 uses bit 0, digit 2 uses bit 1, …, digit 9 uses bit 8.
This means we can track which digits have appeared in a row, column, or 3×3 box using just one integer per row/column/box instead of a hash set.
When we encounter a digit, we compute its bit position and check:
If none of these checks fail, we “turn on” that bit to mark the digit as seen.
This approach is both memory efficient and fast.
Create three arrays of size 9:
rows[i] stores bits for digits seen in row icols[i] stores bits for digits seen in column isquares[i] stores bits for digits seen in 3×3 box iLoop through each cell (r, c) of the board:
".".val = int(board[r][c]) - 1.mask = 1 << val.Check for duplicates:
mask is already set in rows[r], return false.mask is already set in cols[c], return false.mask is already set in squares[(r // 3) * 3 + (c // 3)], return false.Mark the digit as seen:
rows[r] |= maskcols[c] |= masksquares[(r // 3) * 3 + (c // 3)] |= maskIf all cells are processed without conflicts, return true.
Input Sudoku Board:
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 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝BIT REPRESENTATION
Each digit is represented by a single bit:
Digit │ Bit Position │ Mask (binary) │ Mask (decimal)
──────┼──────────────┼───────────────────┼────────────────
1 │ 0 │ 0b000000001 │ 1
2 │ 1 │ 0b000000010 │ 2
3 │ 2 │ 0b000000100 │ 4
4 │ 3 │ 0b000001000 │ 8
5 │ 4 │ 0b000010000 │ 16
6 │ 5 │ 0b000100000 │ 32
7 │ 6 │ 0b001000000 │ 64
8 │ 7 │ 0b010000000 │ 128
9 │ 8 │ 0b100000000 │ 256Data Structures (all initialized to 0):
rows[9] = integers tracking seen digits per row (one int per row)cols[9] = integers tracking seen digits per column (one int per column)squares[9] = integers tracking seen digits per 3x3 box (one int per box)WALKTHROUGH
Step 1: Process cell (0, 0) = '5'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║[5]│ 3 │ . ║ . │ 7 │ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ val = 5 - 1 = 4
mask = 1 << 4 = 0b000010000 (decimal: 16)
Box index: (0/3)*3 + 0/3 = 0
Check duplicates (bitwise AND):
rows[0] & mask = 0 & 16 = 0 → bit not set → not seen
cols[0] & mask = 0 & 16 = 0 → bit not set → not seen
squares[0] & mask = 0 & 16 = 0 → bit not set → not seen
Update (bitwise OR):
rows[0] |= 16 → rows[0] = 0b000010000 (16)
cols[0] |= 16 → cols[0] = 0b000010000 (16)
squares[0] |= 16 → squares[0] = 0b000010000 (16)
No duplicates found → ContinueStep 2: Process cell (0, 1) = '3'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │[3]│ . ║ . │ 7 │ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ val = 3 - 1 = 2
mask = 1 << 2 = 0b000000100 (decimal: 4)
Box index: (0/3)*3 + 1/3 = 0
Check duplicates (bitwise AND):
rows[0] & mask = 16 & 4 = 0 → bit not set → not seen
cols[1] & mask = 0 & 4 = 0 → bit not set → not seen
squares[0] & mask = 16 & 4 = 0 → bit not set → not seen
Update (bitwise OR):
rows[0] |= 4 → rows[0] = 0b000010100 (20)
cols[1] |= 4 → cols[1] = 0b000000100 (4)
squares[0] |= 4 → squares[0] = 0b000010100 (20)
No duplicates found → ContinueStep 3: Process cell (0, 2) = '.' → skip (empty cell)
Step 4: Process cell (0, 3) = '.' → skip (empty cell)
Step 5: Process cell (0, 4) = '7'
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │ 3 │ . ║ . │[7]│ . ║ . │ . │ . ║ ← Current cell highlighted
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ val = 7 - 1 = 6
mask = 1 << 6 = 0b001000000 (decimal: 64)
Box index: (0/3)*3 + 4/3 = 1 ← Different box!
Check duplicates (bitwise AND):
rows[0] & mask = 20 & 64 = 0 → bit not set → not seen
cols[4] & mask = 0 & 64 = 0 → bit not set → not seen
squares[1] & mask = 0 & 64 = 0 → bit not set → not seen
Update (bitwise OR):
rows[0] |= 64 → rows[0] = 0b001010100 (84)
cols[4] |= 64 → cols[4] = 0b001000000 (64)
squares[1] |= 64 → squares[1] = 0b001000000 (64)
No duplicates found → ContinueSTATE AFTER PROCESSING ROW 0
rows[0] = 0b001010100 = 84 (digits 3, 5, 7 seen)
↑ ↑ ↑
bit: 6 4 2
digit: 7 5 3
cols[0] = 0b000010000 = 16 (digit 5)
cols[1] = 0b000000100 = 4 (digit 3)
cols[4] = 0b001000000 = 64 (digit 7)
squares[0] = 0b000010100 = 20 (digits 3, 5)
squares[1] = 0b001000000 = 64 (digit 7)DETECTING A DUPLICATE (Example)
If we later encounter another '5' in row 0:
0 1 2 3 4 5 6 7 8
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
0 ║ 5 │ 3 │ . ║ . │ 7 │[5]║ . │ . │ . ║ ← Duplicate '5' found!
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ val = 5 - 1 = 4
mask = 1 << 4 = 16
Check duplicates (bitwise AND):
rows[0] & mask = 84 & 16 = 16 ← NON-ZERO!
84 = 0b001010100
16 = 0b000010000
─────────────────
AND= 0b000010000 = 16 (bit 4 is already set!)
DUPLICATE FOUND! Return False immediately.Continue processing all cells. If no duplicate is detected (all AND operations return 0), return True.
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [0] * 9
cols = [0] * 9
squares = [0] * 9
for r in range(9):
for c in range(9):
if board[r][c] == ".":
continue
val = int(board[r][c]) - 1
if (1 << val) & rows[r]:
return False
if (1 << val) & cols[c]:
return False
if (1 << val) & squares[(r // 3) * 3 + (c // 3)]:
return False
rows[r] |= (1 << val)
cols[c] |= (1 << val)
squares[(r // 3) * 3 + (c // 3)] |= (1 << val)
return TrueThe 3x3 box index formula (r // 3) * 3 + (c // 3) is easy to get wrong. A common mistake is using (r // 3, c // 3) as a tuple key but forgetting integer division, or computing r // 3 + c // 3 which doesn't uniquely identify boxes.
# Wrong: doesn't uniquely identify boxes
box_idx = r // 3 + c // 3 # Box (0,1) and (1,0) both give 1
# Correct: unique box index 0-8
box_idx = (r // 3) * 3 + c // 3Empty cells are represented by "." and should be skipped entirely. Forgetting to check for empty cells before processing will cause errors or incorrect duplicate detection.
This problem only checks if the current board state is valid, not whether the puzzle is solvable. A board with no duplicates is valid even if it's impossible to complete.
When iterating through the board, make sure each cell is only processed once. Some implementations accidentally check the same digit multiple times when validating rows, columns, and boxes separately.