Skip to content

Commit 212cdfe

Browse files
dbringcclausspre-commit-ci[bot]
authored
Added validate sudoku board function (#9881)
* Added algorithm to deeply clone a graph * Fixed file name and removed a function call * Removed nested function and fixed class parameter types * Fixed doctests * bug fix * Added class decorator * Updated doctests and fixed precommit errors * Cleaned up code * Simplified doctest * Added doctests * Code simplification * Created function which validates sudoku boards * Update matrix/validate_sudoku_board.py * Fixed precommit errors * Removed file accidentally included * Improved readability and simplicity * Add timeit benchmarks * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update validate_sudoku_board.py --------- Co-authored-by: Christian Clauss <cclauss@me.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 71b372f commit 212cdfe

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

matrix/validate_sudoku_board.py

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
LeetCode 36. Valid Sudoku
3+
https://leetcode.com/problems/valid-sudoku/
4+
https://en.wikipedia.org/wiki/Sudoku
5+
6+
Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be
7+
validated according to the following rules:
8+
9+
- Each row must contain the digits 1-9 without repetition.
10+
- Each column must contain the digits 1-9 without repetition.
11+
- Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9
12+
without repetition.
13+
14+
Note:
15+
16+
A Sudoku board (partially filled) could be valid but is not necessarily
17+
solvable.
18+
19+
Only the filled cells need to be validated according to the mentioned rules.
20+
"""
21+
22+
from collections import defaultdict
23+
24+
NUM_SQUARES = 9
25+
EMPTY_CELL = "."
26+
27+
28+
def is_valid_sudoku_board(sudoku_board: list[list[str]]) -> bool:
29+
"""
30+
This function validates (but does not solve) a sudoku board.
31+
The board may be valid but unsolvable.
32+
33+
>>> is_valid_sudoku_board([
34+
... ["5","3",".",".","7",".",".",".","."]
35+
... ,["6",".",".","1","9","5",".",".","."]
36+
... ,[".","9","8",".",".",".",".","6","."]
37+
... ,["8",".",".",".","6",".",".",".","3"]
38+
... ,["4",".",".","8",".","3",".",".","1"]
39+
... ,["7",".",".",".","2",".",".",".","6"]
40+
... ,[".","6",".",".",".",".","2","8","."]
41+
... ,[".",".",".","4","1","9",".",".","5"]
42+
... ,[".",".",".",".","8",".",".","7","9"]
43+
... ])
44+
True
45+
>>> is_valid_sudoku_board([
46+
... ["8","3",".",".","7",".",".",".","."]
47+
... ,["6",".",".","1","9","5",".",".","."]
48+
... ,[".","9","8",".",".",".",".","6","."]
49+
... ,["8",".",".",".","6",".",".",".","3"]
50+
... ,["4",".",".","8",".","3",".",".","1"]
51+
... ,["7",".",".",".","2",".",".",".","6"]
52+
... ,[".","6",".",".",".",".","2","8","."]
53+
... ,[".",".",".","4","1","9",".",".","5"]
54+
... ,[".",".",".",".","8",".",".","7","9"]
55+
... ])
56+
False
57+
>>> is_valid_sudoku_board([["1", "2", "3", "4", "5", "6", "7", "8", "9"]])
58+
Traceback (most recent call last):
59+
...
60+
ValueError: Sudoku boards must be 9x9 squares.
61+
>>> is_valid_sudoku_board(
62+
... [["1"], ["2"], ["3"], ["4"], ["5"], ["6"], ["7"], ["8"], ["9"]]
63+
... )
64+
Traceback (most recent call last):
65+
...
66+
ValueError: Sudoku boards must be 9x9 squares.
67+
"""
68+
if len(sudoku_board) != NUM_SQUARES or (
69+
any(len(row) != NUM_SQUARES for row in sudoku_board)
70+
):
71+
error_message = f"Sudoku boards must be {NUM_SQUARES}x{NUM_SQUARES} squares."
72+
raise ValueError(error_message)
73+
74+
row_values: defaultdict[int, set[str]] = defaultdict(set)
75+
col_values: defaultdict[int, set[str]] = defaultdict(set)
76+
box_values: defaultdict[tuple[int, int], set[str]] = defaultdict(set)
77+
78+
for row in range(NUM_SQUARES):
79+
for col in range(NUM_SQUARES):
80+
value = sudoku_board[row][col]
81+
82+
if value == EMPTY_CELL:
83+
continue
84+
85+
box = (row // 3, col // 3)
86+
87+
if (
88+
value in row_values[row]
89+
or value in col_values[col]
90+
or value in box_values[box]
91+
):
92+
return False
93+
94+
row_values[row].add(value)
95+
col_values[col].add(value)
96+
box_values[box].add(value)
97+
98+
return True
99+
100+
101+
if __name__ == "__main__":
102+
from doctest import testmod
103+
from timeit import timeit
104+
105+
testmod()
106+
print(timeit("is_valid_sudoku_board(valid_board)", globals=globals()))
107+
print(timeit("is_valid_sudoku_board(invalid_board)", globals=globals()))

0 commit comments

Comments
 (0)