我觉得这题的思路还是很简单的,回溯法
就是模拟人解数独时的简单想法:
人在解数独的时候要注意每一行、每一列、每一个子数独中哪些数字已经被使用过了;
一行一行的进行填充,填充完一行就到下一行继续填充;
如果一个单元格中不为空,则去下一个单元格;
如果一个单元格为空,我们就看一下这个单元格所属的行、列、子数独中有哪些数字没有使用过,就将未使用过的数字填入单元格,并且记录这个被填入的数字在此单元格所属的行、列、子数独中已经被使用过了;
如果出现因为之前填充空格时选择不佳,导致无法继续填写空格的情况,就逐步擦除之前填入的数字,并将被擦除的数字在所属的行、列、子数独中设置为未使用的状态后,重新选择下一个未使用过的数字进行填充,尝试继续完成填充;
如果已经填充完所有行,即成功解数独。
思路理清后,代码很快就写好了:
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
{
if (board[i][j] != '.')
{
rows[i][board[i][j] - '0' - 1] = true;
cols[j][board[i][j] - '0' - 1] = true;
blocks[i / 3 * 3 + j / 3][board[i][j] - '0' - 1] = true;
}
}
DFS(board, 0, 0);
}
//深度遍历,row记录当前要填写的行,col记录当前要填写的列
void DFS(vector<vector<char>>& board, int row, int col)
{
//0-8行都已经填写,解数独完毕
if (row == 9) {
finished = true;
return;
}
//不是空白格,不需要填写,继续向后移动
if (board[row][col] != '.')
{
//如果本行已经是最后一列,则继续填写下一行的第一列;否则继续当前行的下一列。
if (col == 8) DFS(board, row + 1, 0);
else DFS(board, row, col + 1);
}
else//是空白格,按顺序将当前行、列、子数独未使用的数字尝试填入空白格
{
for (char number = '1'; number <= '9'; number++)
{
if (!rows[row][number - '0' - 1] && !cols[col][number - '0' - 1] && !blocks[row / 3 * 3 + col / 3][number - '0' - 1])
{
board[row][col] = number;
rows[row][number - '0' - 1] = cols[col][number - '0' - 1] = blocks[row / 3 * 3 + col / 3][number - '0' - 1] = true;
//填写完毕当前空白格,继续填写下一格
if (col == 8)DFS(board, row + 1, 0);
else DFS(board, row, col + 1);
//如果当前尝试填入的数字不能成功解数独(导致后序空白格无法填写),则回溯
if (!finished)
{
//擦除填入的数字,并更新被擦除数字的状态
board[row][col] = '.';
rows[row][number - '0' - 1] = cols[col][number - '0' - 1] = blocks[row / 3 * 3 + col / 3][number - '0' - 1] = false;
}
}
}
}
}
private:
bool rows[9][9] = { false };//rows[i][j]为true表示第i+1行的数字j+1已经被使用了
bool cols[9][9] = { false };//cols[i][j]为true表示第i+1列的数字j+1已经被使用了
bool blocks[9][9] = { false };//cols[i][j]为true表示第i+1个子数独中数字j+1已经被使用了
bool finished = false;
};
来源:CSDN
作者:ShenHang_
链接:https://blog.csdn.net/ShenHang_/article/details/104636831