diff --git a/include/s0037_sudoku_solver.hpp b/include/s0037_sudoku_solver.hpp new file mode 100644 index 0000000..4cc4dac --- /dev/null +++ b/include/s0037_sudoku_solver.hpp @@ -0,0 +1,16 @@ +#ifndef S0037_SUDOKU_SOLVER_HPP +#define S0037_SUDOKU_SOLVER_HPP + +#include +#include +#include +#include + +using namespace std; + +class Solution { + public: + void solveSudoku(vector>& board); +}; + +#endif diff --git a/src/s0037_sudoku_solver.cpp b/src/s0037_sudoku_solver.cpp new file mode 100644 index 0000000..e010dbf --- /dev/null +++ b/src/s0037_sudoku_solver.cpp @@ -0,0 +1,80 @@ +#include "s0037_sudoku_solver.hpp" + +#include +#include + +// 返回结果为当前传递进去的数独是否存在解 +bool recusiveSolveSudoku(vector> &board, + vector> &rows, + vector> &cols, + vector> &grids, int row, + int col) { + int size = board.size(); + // 边界校验 + if (col == size) { + // 进入下一行 + col = 0; + row++; + // 填充完成,返回 True + if (row == size) { + return true; + } + } + // 如果不为空则跳过,填充下一个 + if (board[row][col] != '.') { + return recusiveSolveSudoku(board, rows, cols, grids, row, col + 1); + } else { // 否则开始填充 + // 尝试填充 1 ~ 9 + for (char num{'1'}; num <= '9'; ++num) { + int gridIndex = static_cast(floor(row / 3)) + + 3 * static_cast(floor(col / 3)); + // 如果这个数字还没有出现过 + if (!(rows[row].count(num) == 1 || cols[col].count(num) == 1 || + grids[gridIndex].count(num) == 1)) { + // 先把这个数字填进去 + rows[row][num] = true; + cols[col][num] = true; + grids[gridIndex][num] = true; + board[row][col] = num; + // 然后试试看填进去后下一个能不能解 + // 如果下一个能解的话,现在这个肯定能解 + if (recusiveSolveSudoku(board, rows, cols, grids, row, col + 1)) { + return true; + } + // 如果不能解,那么说明这个数字填错了,把它重新设为空,然后尝试下一个数字 + board[row][col] = '.'; + rows[row].erase(num); + cols[col].erase(num); + grids[gridIndex].erase(num); + } + } + } + return false; +} + +void Solution::solveSudoku(vector> &board) { + // 每个行/列/单元格中某个数字是否出现过 + vector> rows; + vector> cols; + vector> grids; + // 初始化 + int size = board.size(); + for (int i{0}; i < size; ++i) { + rows.push_back(unordered_map{}); + cols.push_back(unordered_map{}); + grids.push_back(unordered_map{}); + } + for (int row{0}; row < size; ++row) { + for (int col{0}; col < size; ++col) { + if (board[row][col] != '.') { + rows[row][board[row][col]] = true; + cols[col][board[row][col]] = true; + int gridIndex = static_cast(floor(row / 3)) + + 3 * static_cast(floor(col / 3)); + grids[gridIndex][board[row][col]] = true; + } + } + } + // 从 (0, 0) 开始递归求解 + recusiveSolveSudoku(board, rows, cols, grids, 0, 0); +} diff --git a/tests/s0037_sudoku_solver.cpp b/tests/s0037_sudoku_solver.cpp new file mode 100644 index 0000000..9033a47 --- /dev/null +++ b/tests/s0037_sudoku_solver.cpp @@ -0,0 +1,27 @@ +#include "s0037_sudoku_solver.hpp" + +#include + +TEST(Problem37, Case1) { + vector> board{{'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'}}; + vector> expected{{'5', '3', '4', '6', '7', '8', '9', '1', '2'}, + {'6', '7', '2', '1', '9', '5', '3', '4', '8'}, + {'1', '9', '8', '3', '4', '2', '5', '6', '7'}, + {'8', '5', '9', '7', '6', '1', '4', '2', '3'}, + {'4', '2', '6', '8', '5', '3', '7', '9', '1'}, + {'7', '1', '3', '9', '2', '4', '8', '5', '6'}, + {'9', '6', '1', '5', '3', '7', '2', '8', '4'}, + {'2', '8', '7', '4', '1', '9', '6', '3', '5'}, + {'3', '4', '5', '2', '8', '6', '1', '7', '9'}}; + Solution solution; + solution.solveSudoku(board); + EXPECT_EQ(board, expected); +}