在上一篇LeetCode题解:数独游戏有效性检测介绍了如何判断一个待填写的数独是否有效,本篇将进一步通过回溯法 求解填充一个完整的数独。
图示:
求解结果:
解题思路:
/*
回溯法:
1、遍历输入单元格,如果一个单元格为空,则填入该行为空的数字,更新对应的行、列、子单元;
2、判断填入数字是否满足数独有效性要求,如果不满足,填入该空格可填入的另一个有效数字;
3、重复1,2过程直到每行扫描结束,进行下一行扫描
*/
(注释:该方法类似填入一个数字,不断尝试数字,如果填错了就把填入的数字删除,换一个数字重新尝试。玩过数独,其实有很多有意思的解法,感兴趣的同学可以搜索 更有趣的解法。这样对求解是很复杂的,但对机器来说却很方便。)
c++代码实现:
class Solution {
//init state
bool rows[9][9];
bool cols[9][9];
bool boxes[9][9];
public:
bool solveSudoku(vector<vector<char>>& board, int x, int y) {
if (y == board[x].size())
{
x++;
y = 0;
}
if (x == board.size()){
return true;
}
//fill value to .
if (board[x][y] != '.'){
return solveSudoku(board, x, y + 1);
}
// find . to insert value
for (char c = '1'; c <= '9'; c++)
{
int box = x / 3 * 3 + y / 3;
if (rows[x][c - '1'] || cols[y][c - '1'] || boxes[box][c - '1']){
continue;
}
//insert value
board[x][y] = c;
//update state
rows[x][c - '1'] = cols[y][c - '1'] = boxes[box][c - '1'] = true;
if (solveSudoku(board, x, y + 1)){
return true;
}
//back track, set . do it again
rows[x][c - '1'] = cols[y][c - '1'] = boxes[box][c - '1'] = false;
board[x][y] = '.';
}
return false;
}
void solveSudoku(vector<vector<char>>& board) {
memset(rows, 0, sizeof(rows));
memset(cols, 0, sizeof(cols));
memset(boxes, 0, sizeof(boxes));
// fill rows
for (int i = 0; i < board.size(); i++){
for (int j = 0; j < board[i].size(); j++)
{
char c = board[i][j];
if (c == '.'){
continue;
}
//set value to update state
int box = i / 3 * 3 + j / 3;
rows[i][c - '1'] = cols[j][c - '1'] = boxes[box][c - '1'] = true;
}
}
//sub function to fill the . with right value
solveSudoku(board, 0, 0);
}
};
source link:sudoku-solver
reference:https://leetcode.com/problems/sudoku-solver/discuss/394629/C%2B%2B-faster-than-100
Practice makes perfect !