Problem
You are given a a 9 x 9 Sudoku board board. A Sudoku board is valid if the following rules are followed:
- Each row must contain the digits
1-9without duplicates. - Each column must contain the digits
1-9without duplicates. - Each of the nine
3 x 3sub-boxes of the grid must contain the digits1-9without 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:
Transclude of 2_M-SpV7SZTmw9YHC734tSHQ.avif
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 digit1-9or'.'
Solutions
1. Hashing
Time Complexity: | Space Complexity:
We can solve the problem by iterating through all rows and columns, and adding elements to related dictionaries. If we encounter that an element is already present in its dictionary, we return false. In total, we will have 9 column dictionaries, 9 row dictionaries, and 9 sub-box dictionaries. To calculate the related dictionary for a sub-box, we divide row and col by 3, as it will round the number, making it an integer.
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
cols = defaultdict(set)
rows = defaultdict(set)
subboxes = defaultdict(set)
for row in range(len(board)):
for col in range(len(board[0])):
val = board[row][col]
if val == ".":
continue
if val in cols[col]:
return False
if val in rows[row]:
return False
if val in subboxes[(row // 3, col // 3)]:
return False
cols[col].add(val)
rows[row].add(val)
subboxes[(row // 3, col // 3)].add(val)
return True2. Arrays
Time Complexity: | Space Complexity:
Alternatively, we can utilize lists to keep track of elements.
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
cols = defaultdict(list)
rows = defaultdict(list)
subboxes = defaultdict(list)
for row in range(len(board)):
for col in range(len(board[0])):
val = board[row][col]
if val == ".":
continue
if val in cols[col]:
return False
if val in rows[row]:
return False
if val in subboxes[(row // 3, col // 3)]:
return False
cols[col].append(val)
rows[row].append(val)
subboxes[(row // 3, col // 3)].append(val)
return True
🏆 3. Bitmasking
Time Complexity: | Space Complexity:
To improve our solution further and reduce the amount of space used, we use bitmasking. By representing the presence of each number in rows, columns, and sub-boxes with bits in an integer, we can efficiently check and mark the existence of numbers.
To check if a number is already present in a row, column, or sub-box, we use the bitwise AND operation: cols[col] & (1 << val)
1 << valcreates a bitmask with only theval-th bit set to 1cols[col] & (1 << val)checks if theval-th bit is set incols[col]. If it is non-zero, the number is already present
To mark a number as present, we use the bitwise OR operation: cols[col] |= (1 << val)
1 << valcreates a bitmask with only theval-th bit set to 1cols[col] |= (1 << val)sets theval-th bit incols[col], marking the number as present
from typing import List
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
cols = [0] * 9
rows = [0] * 9
subboxes = [0] * 9
for row in range(len(board)):
for col in range(len(board[0])):
if board[row][col] == ".":
continue
val = int(board[row][col]) - 1
sb = (row // 3) * 3 + (col // 3)
if cols[col] & (1 << val):
return False
if rows[row] & (1 << val):
return False
if subboxes[sb] & (1 << val):
return False
cols[col] |= (1 << val)
rows[row] |= (1 << val)
subboxes[sb] |= (1 << val)
return True