37. 解数独
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
思路
直接通过回溯法来对每个空格进行枚举可填入数字即可,使用一个行标示、列标示、方格标示来标记数字在该行、列、方格中是否出现,如果某个位置无法填入任何数,就回溯枚举下一个数。
代码
class Solution {
private:
bool line[9][9];
bool column[9][9];
bool block[3][3][9];
vector<pair<int, int>> spaces;
bool valid;
public:
void dfs(vector<vector<char>>& board, int index) {
//填完了
if(index == spaces.size()) {
valid = true;
return;
}
//取出可填位置
auto [x, y] = spaces[index];
for(int i = 0; i < 9 && !valid; i++) {
//该数字在行、列、格子还没出现
if(!line[x][i] && !column[y][i] && !block[x / 3][y / 3][i]) {
//填入
board[x][y] = '1' + i;
//设置标志
line[x][i] = column[y][i] = block[x / 3][y / 3][i] = true;
dfs(board, index + 1);
//回溯,取消标志
line[x][i] = column[y][i] = block[x / 3][y / 3][i] = false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line, false, sizeof(line));
memset(column, false, sizeof(column));
memset(block, false, sizeof(block));
valid = false;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
//统计空格子
if(board[i][j] == '.') {
spaces.push_back(make_pair(i, j));
}
//已经出现的数
else {
int number = board[i][j] - '1';
line[i][number] = column[j][number] = block[i / 3][j / 3][number] = true;
}
}
}
dfs(board, 0);
}
};