From 012f7b9e44359a4fa33b04f247fdf0a8e0958198 Mon Sep 17 00:00:00 2001 From: pro100ton Date: Fri, 14 Feb 2025 20:36:39 +0300 Subject: [PATCH] Add sudoku --- neetcode/arrays/valid_sudoku/README.md | 89 ++++++++++++++++++++++++++ neetcode/arrays/valid_sudoku/main.py | 74 +++++++++++++++++++++ poetry.lock | 9 +-- pyrightconfig.json | 4 ++ 4 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 neetcode/arrays/valid_sudoku/README.md create mode 100644 neetcode/arrays/valid_sudoku/main.py create mode 100644 pyrightconfig.json diff --git a/neetcode/arrays/valid_sudoku/README.md b/neetcode/arrays/valid_sudoku/README.md new file mode 100644 index 0000000..2943372 --- /dev/null +++ b/neetcode/arrays/valid_sudoku/README.md @@ -0,0 +1,89 @@ +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-9 without duplicates. +Each column must contain the digits 1-9 without duplicates. +Each of the nine 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: true +Example 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: false +Explanation: There are two 1's in the top-left 3x3 sub-box. + +Constraints: + +board.length == 9 +board[i].length == 9 +board[i][j] is a digit 1-9 or '.'. + +# Решение +Пусть будет матрица 3х3 где будут храниться числа в каждом квадрате валидации, т.е. +``` +sq = [ + (), (), (), + (), (), (), + (), (), (), +] +``` +Когда начнем проходить по двумерной матрице - будем смотреть на номер строк и остаток деления на три от длины проверяемого столбца, чтобы определять в какой квадрат писать + + +i // 3 +[ + 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 + + 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 + + 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2 +] + +j // 3 +[ + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 + + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 + + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 + 0 0 0 1 1 1 2 2 2 +] + diff --git a/neetcode/arrays/valid_sudoku/main.py b/neetcode/arrays/valid_sudoku/main.py new file mode 100644 index 0000000..d769d42 --- /dev/null +++ b/neetcode/arrays/valid_sudoku/main.py @@ -0,0 +1,74 @@ +from typing import Dict, List, Set +import pytest +from collections import defaultdict + + +class Solution: + """Bruteforce solution (4 hints)""" + + def isValidSudoku(self, board: List[List[str]]) -> bool: + squares: Dict = { + "00": set(), + "01": set(), + "02": set(), + "10": set(), + "11": set(), + "12": set(), + "20": set(), + "21": set(), + "22": set(), + } + lines = defaultdict(set) + for i in range(0, len(board)): + for j in range(0, len(board[i])): + board_elem = board[i][j] + squares_index = f"{i // 3}{j // 3}" + squares_index_len = len(squares[squares_index]) + lines_index_len = len(lines[squares_index]) + if board_elem != ".": + squares[squares_index].add(board_elem) + if len(squares[squares_index]) == squares_index_len: + return False + lines[f"{i}{j}"].add(board_elem) + if len(lines[f"{i}{j}"]) == lines_index_len: + breakpoint() + return False + return True + + +@pytest.mark.parametrize( + "input_value, expected_value", + [ + ( + [ + ["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"], + ], + True, + ), + ( + [ + ["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"], + ], + False, + ), + ], +) +def test_solution(input_value, expected_value): + s = Solution() + assert s.isValidSudoku(board=input_value) == expected_value diff --git a/poetry.lock b/poetry.lock index 0d3503f..951863e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -16,7 +15,6 @@ files = [ name = "exceptiongroup" version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -31,7 +29,6 @@ test = ["pytest (>=6)"] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -43,7 +40,6 @@ files = [ name = "packaging" version = "24.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -55,7 +51,6 @@ files = [ name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -71,7 +66,6 @@ testing = ["pytest", "pytest-benchmark"] name = "pytest" version = "8.3.4" description = "pytest: simple powerful testing with Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -94,7 +88,6 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments name = "tomli" version = "2.2.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.8" files = [ diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..67fed16 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,4 @@ +{ + "venv": ".venv", + "venvPath": "/Users/antonsalimov/Projects/Learning/algos_and_structures", +}