diff --git a/leetcode/DIRECTORY.md b/leetcode/DIRECTORY.md index 05c7c1e8..06e426fe 100644 --- a/leetcode/DIRECTORY.md +++ b/leetcode/DIRECTORY.md @@ -26,6 +26,7 @@ | 29 | [Divide Two Integers](https://leetcode.com/problems/divide-two-integers/) | [C](./src/29.c) | Medium | | 32 | [Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/) | [C](./src/32.c) | Hard | | 35 | [Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [C](./src/35.c) | Easy | +| 37 | [Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) | [C](./src/37.c) | Hard | | 38 | [Count and Say](https://leetcode.com/problems/count-and-say/) | [C](./src/38.c) | Easy | | 42 | [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) | [C](./src/42.c) | Hard | | 53 | [Maximum Subarray](https://leetcode.com/problems/maximum-subarray/) | [C](./src/53.c) | Easy | diff --git a/leetcode/src/37.c b/leetcode/src/37.c new file mode 100644 index 00000000..7d8cae11 --- /dev/null +++ b/leetcode/src/37.c @@ -0,0 +1,88 @@ +int** initSet(int size){ + int** result = (int**) malloc(size * sizeof(int*)); + for (int i = 0; i < size; i++) { + result[i] = (int*)calloc(size, sizeof(int)); + } + + return result; +} + +// Returns the id of triplet which the point (i, j) belongs to +int getTripletId(int i, int j){ + return (i / 3) * 3 + (j / 3); +} + +// Recursive function which populates sudoku board. +bool sudokuSolver(int startI, int startJ, char** board, int boardSize, int* boardColSize, int** horizontalsSets, int** verticalsSets, int** tripletsSets){ + for (int i = startI; i < boardSize; i++) { + for (int j = startJ; j < boardColSize[i]; j++) { + if (board[i][j] != '.'){ + continue; + } + + // Find the sets of the current point (i, j) + int* horizontalSet = horizontalsSets[i]; + int* verticalSet = verticalsSets[j]; + int* tripletsSet = tripletsSets[getTripletId(i, j)]; + + for (int z = 1; z < 10; z++) { + if (horizontalSet[z] || verticalSet[z] || tripletsSet[z]){ + continue; + } + + // If the z doesn't belong to occupations sets, we check this value to be in place + horizontalSet[z] = 1; + verticalSet[z] = 1; + tripletsSet[z] = 1; + + if (sudokuSolver(i, j + 1, board, boardSize, boardColSize, horizontalsSets, verticalsSets, tripletsSets)){ + board[i][j] = z + '0'; + return true; + } + + horizontalSet[z] = 0; + verticalSet[z] = 0; + tripletsSet[z] = 0; + } + + // We tried all possible values in range 1-10. No variants - returns false; + return false; + } + + // startJ to begin of the row. + startJ = 0; + } + + // Reach it when the end of the board - then all previous values are setup correctly. + return true; +} + +// Use backtracking +void solveSudoku(char** board, int boardSize, int* boardColSize){ + // Declare sets for cheking occupation of numbers by horizontals, verticals lines and triplets. + int** horizontalsSets = initSet(boardSize + 1); + int** verticalsSets = initSet(boardSize + 1); + int** tripletsSets = initSet(getTripletId(boardSize + 1, boardSize + 1)); + + // Populate sets with values from the board. + for (int i = 0; i < boardSize; i++) { + for (int j = 0; j < boardColSize[i]; j++) { + if (board[i][j] == '.'){ + continue; + } + + int value = board[i][j] - '0'; + horizontalsSets[i][value] = 1; + verticalsSets[j][value] = 1; + tripletsSets[getTripletId(i, j)][value] = 1; + } + } + + // Solving + sudokuSolver(0, 0, board, boardSize, boardColSize, horizontalsSets, verticalsSets, tripletsSets); + + // Free resources + free(horizontalsSets); + free(verticalsSets); + free(tripletsSets); +}