diff --git a/README.md b/README.md index 93a00d2..3db290f 100644 --- a/README.md +++ b/README.md @@ -76,4 +76,5 @@ - [Task #4](src/neetcode/arrays-&-hashing/group-anagrams) - _Group Anagrams_ - _[check the task](https://neetcode.io/problems/anagram-groups)_ - [Task #5](src/neetcode/arrays-&-hashing/top-k-frequent-elements) - _Top K Frequent Elements_ - _[check the task](https://neetcode.io/problems/top-k-elements-in-list)_ - [Task #6](src/neetcode/arrays-&-hashing/encode-and-decode-strings) - _Encode And Decode Strings_ - _[check the task](https://neetcode.io/problems/string-encode-and-decode)_ - - [Task #7](src/neetcode/arrays-&-hashing/product-of-array-except-self) - _Products of Array Except Self_ - _[check the task](https://neetcode.io/problems/products-of-array-discluding-self)_ \ No newline at end of file + - [Task #7](src/neetcode/arrays-&-hashing/product-of-array-except-self) - _Products of Array Except Self_ - _[check the task](https://neetcode.io/problems/products-of-array-discluding-self)_ + - [Task #8](src/neetcode/arrays-&-hashing/valid-sudoku) - _Valid Sudoku_ - _[check the task](https://neetcode.io/problems/valid-sudoku)_ \ No newline at end of file diff --git a/src/neetcode/arrays-&-hashing/valid-sudoku/solution.test.ts b/src/neetcode/arrays-&-hashing/valid-sudoku/solution.test.ts new file mode 100644 index 0000000..33a7116 --- /dev/null +++ b/src/neetcode/arrays-&-hashing/valid-sudoku/solution.test.ts @@ -0,0 +1,63 @@ +import { isValidSudoku } from './solution'; + +describe('Valid Sudoku | NeetCode RoadMap | Testcases', () => { + test('#1 Valid', () => { + const 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'], + ]; + expect(isValidSudoku(board)).toBe(true); + }); + + test('#2 Invalid Line', () => { + const board = [ + ['.', '.', '.', '.', '.', '.', '.', '.', '.'], + ['.', '.', '.', '.', '.', '.', '.', '.', '.'], + ['.', '9', '.', '.', '.', '.', '.', '.', '1'], + ['8', '.', '.', '.', '.', '.', '.', '.', '.'], + ['.', '9', '9', '3', '5', '7', '.', '.', '.'], + ['.', '.', '.', '.', '.', '.', '.', '4', '.'], + ['.', '.', '.', '8', '.', '.', '.', '.', '.'], + ['.', '1', '.', '.', '.', '.', '4', '.', '9'], + ['.', '.', '.', '5', '.', '4', '.', '.', '.'], + ]; + expect(isValidSudoku(board)).toBe(false); + }); + + test('#3 Invalid Column', () => { + const board = [ + ['1', '2', '.', '.', '3', '.', '.', '.', '.'], + ['4', '.', '.', '5', '.', '.', '.', '.', '.'], + ['.', '9', '1', '.', '.', '.', '.', '.', '3'], + ['5', '.', '.', '.', '6', '.', '.', '.', '4'], + ['.', '.', '.', '8', '.', '3', '.', '.', '5'], + ['7', '.', '.', '.', '2', '.', '.', '.', '6'], + ['.', '.', '.', '.', '.', '.', '2', '.', '.'], + ['1', '.', '.', '4', '1', '9', '.', '.', '8'], + ['.', '.', '.', '.', '8', '.', '.', '7', '9'], + ]; + expect(isValidSudoku(board)).toBe(false); + }); + + test('#4 Invalid Square', () => { + const 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'], + ]; + expect(isValidSudoku(board)).toBe(false); + }); +}); diff --git a/src/neetcode/arrays-&-hashing/valid-sudoku/solution.ts b/src/neetcode/arrays-&-hashing/valid-sudoku/solution.ts new file mode 100644 index 0000000..921b88a --- /dev/null +++ b/src/neetcode/arrays-&-hashing/valid-sudoku/solution.ts @@ -0,0 +1,50 @@ +/** + * @param {character[][]} board + * @return {boolean} `true` if the Sudoku board is valid, `false` otherwise + */ +export const isValidSudoku = (board: string[][]): boolean => { + for (const line of board) { + const numsCount = Array.from({ length: board.length + 1 }).fill(0); + for (const el of line) { + const num = Number(el); + if (!isNaN(num)) { + numsCount[num]++; + if (numsCount[num] > 1) { + return false; + } + } + } + } + + for (let i = 0; i < board.length; i++) { + const numsCount = Array.from({ length: board.length + 1 }).fill(0); + for (let j = 0; j < board[i].length; j++) { + const num = Number(board[j][i]); + if (!isNaN(num)) { + numsCount[num]++; + if (numsCount[num] > 1) { + return false; + } + } + } + } + + for (let i = 0; i < board.length; i += 3) { + for (let j = 0; j < board[i].length; j += 3) { + const numsCount = Array.from({ length: board.length + 1 }).fill(0); + for (let k = 0; k < 3; k++) { + for (let l = 0; l < 3; l++) { + const num = Number(board[i + k][j + l]); + if (!isNaN(num)) { + numsCount[num]++; + if (numsCount[num] > 1) { + return false; + } + } + } + } + } + } + + return true; +};