链接
https://leetcode-cn.com/problems/sudoku-solver/
耗时
解题:2 h 30 min
题解:14 min
题意
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
一个数独。
答案被标成红色。
Note:
- 给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
- 你可以假设给定的数独只有唯一解。
- 给定数独永远是 9x9 形式的。
思路
找到每个空格的所有可能解,然后选择一个最少可能解的位置开始在它的位置 dfs 尝试它的所有可能解。首先假设一个可能解,赋值到 board,然后以这个 board 继续以上工作。回溯回来再把当前位置变成 ‘.’ 继续尝试它的下一个可能解。
时间复杂度:?
AC代码
class Solution {
private:
bool ans = false;
public:
vector<vector<vector<int>>> possibility(vector<vector<char>>& board) {
vector<vector<vector<int>>> res;
res.resize(9, vector<vector<int>>(9));
for(int i = 0; i < 9; ++i) {
for(int j = 0; j < 9; ++j) {
if(board[i][j] == '.') {
int tmp[10] = {0};
// block
int r = 3*(i/3);
int c = 3*(j/3);
for(int p = r; p < r+3; ++p) {
for(int q = c; q < c+3; ++q) {
if(board[p][q] != '.') {
tmp[board[p][q]-'0'] = 1;
}
}
}
// row
for(int k = 0; k < 9; ++k) {
if(k == j) continue;
if(board[i][k] != '.') {
tmp[board[i][k]-'0'] = 1;
}
}
// column
for(int k = 0; k < 9; ++k) {
if(k == i) continue;
if(board[k][j] != '.') {
tmp[board[k][j]-'0'] = 1;
}
}
for(int k = 1; k <= 9; ++k) {
if(tmp[k] == 0) {
res[i][j].push_back(k);
}
}
}
}
}
return res;
}
bool checkPosLawful(int i, int j, vector<vector<char>>& board) {
int tmp[10] = {0};
// block
int r = 3*(i/3);
int c = 3*(j/3);
for(int p = r; p < r+3; ++p) {
for(int q = c; q < c+3; ++q) {
if(board[p][q] != '.') {
if(tmp[board[p][q]-'0'] == 1) {
return false;
}
tmp[board[p][q]-'0'] = 1;
}
}
}
// row
memset(tmp, 0, sizeof(tmp));
for(int k = 0; k < 9; ++k) {
if(k == j) continue;
if(board[i][k] != '.') {
if(tmp[board[i][k]-'0'] == 1) {
return false;
}
tmp[board[i][k]-'0'] = 1;
}
}
// column
memset(tmp, 0, sizeof(tmp));
for(int k = 0; k < 9; ++k) {
if(k == i) continue;
if(board[k][j] != '.') {
if(tmp[board[k][j]-'0'] == 1) {
return false;
}
tmp[board[k][j]-'0'] = 1;
}
}
return true;
}
bool success(vector<vector<char>>& board) {
for(auto r : board) {
for(auto c : r) {
if(c == '.')
return false;
}
}
return true;
}
void solveSudoku(vector<vector<char>>& board) {
// success
if(success(board)) {
ans = true;
return ;
}
// get all '.' cell's possibility
vector<vector<vector<int>>> res = possibility(board);
// find mini possibility number position
int minPoss = 10;
pair<int, int> pos;
for(int i = 0; i < 9; ++i) {
for(int j = 0; j < 9; ++j) {
if(res[i][j].size() > 0 && res[i][j].size() < minPoss) {
minPoss = res[i][j].size();
pos.first = i;
pos.second = j;
}
}
}
// try mini position's all possibility
for(auto x : res[pos.first][pos.second]) {
board[pos.first][pos.second] = x+'0';
if(checkPosLawful(pos.first, pos.second, board)) {
solveSudoku(board);
}
if(ans == true) return ;
board[pos.first][pos.second] = '.';
}
}
};