解数独
解数独和n皇后问题一样都用到了回溯思想。但解数独会更加复杂。
- 数独每次需要考虑三个状态,这个和n皇后一样,行,列,九宫格。
- 数独的三个状态没法像n皇后一样推导出下一层dfs时的状态,因此需要在回溯前就把每一行,列,九宫格的状态都记录下来。
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
int rows[9], cols[9], sqrs[3][3];
for (int i = 0; i < 9; i++) {
int s = 0;
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.')
s |= (1 << board[i][j] - '0');
}
rows[i] = s;
}
for (int j = 0; j < 9; j++) {
int s = 0;
for (int i = 0; i < 9; i++) {
if (board[i][j] != '.')
s |= (1 << board[i][j] - '0');
}
cols[j] = s;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int k = i * 3, l = j * 3;
int s = 0;
for (int m = k; m < k + 3; m++) {
for (int n = l; n < l + 3; n++) {
if (board[m][n] != '.')
s |= (1 << board[m][n] - '0');
}
}
sqrs[i][j] = s;
}
}
dfs(board, rows, cols, sqrs, 0, 0);
}
bool dfs(vector<vector<char>>& board, int rows[9], int cols[9],
int sqrs[3][3], int i, int j) {
if (i == 9)
return true;
int ni = i, nj = j;
if (j == 8) {
nj = 0;
ni++;
} else {
nj++;
}
if (board[i][j] == '.') {
int s = rows[i] | cols[j] | sqrs[i / 3][j / 3];
if (s == 1022)
return false;
for (int k = 1; k < 10; k++) {
int bit = 1 << k;
if (!(s & bit)) {
board[i][j] = '0' + k;
rows[i] |= bit;
cols[j] |= bit;
sqrs[i / 3][j / 3] |= bit;
if (dfs(board, rows, cols, sqrs, ni, nj)) {
return true;
}
board[i][j] = '.';
rows[i] ^= bit;
cols[j] ^= bit;
sqrs[i / 3][j / 3] ^= bit;
}
}
return false;
} else {
return dfs(board, rows, cols, sqrs, ni, nj);
}
}
};