问题
37:编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
一、解题思路
使用二维递归来暴力搜索,递归的结束条件是找到满足条件的方案就立刻返回,因为正确方案只有一个,递归返回值需要bool类型,这样便于实现找到解决方案立刻返回,而不是进行回溯修改原来的方案。
本题不需要写终止条件,因为找到解决方案自然就立刻返回了,这也是暴力搜索的本质。
遍历逻辑是用两个for循环遍历行和列,一个有趣的地方是填通过判断位置是否是数字来保证下一层的棋盘一定比上一层的棋盘多一个数,因为上一层棋盘放了数后,下一层通过判断是否有数字来跳过本次循环,另外需要使用一个for循环来判断放数字的可能性。
二、代码
class Solution {
private:
bool backtracking(int row, int col, vector<vector<char>>& board){
for (int i=row; i<board.size(); i++){
for (int j=col; j<board.size(); j++){
if (board[i][j]!='.'){
continue;
}
for (char k='1'; k<='9'; k++){
if (isvalid(board, i, j, k)){
board[i][j] = k;
if (backtracking(i, j, board)) return true;
board[i][j] = '.';
}
}
return false;
}
}
return true;
}
bool isvalid(vector<vector<char>>& board, int row, int col, char val){
for (int i=0; i<9; i++){
if (board[row][i]==val){
return false;
}
}
for (int i=0; i<9; i++){
if (board[i][col]==val){
return false;
}
}
int startRow = (row/3) * 3;
int startCol = (col/3) * 3;
for (int i = startRow; i<startRow+3; i++){
for (int j = startCol; j<startCol+3; j++){
if (board[i][j]==val){
return false;
}
}
}
return true;
}
public:
void solveSudoku(vector<vector<char>>& board) {
backtracking(0, 0, board);
}
};
总结
本题需要很好的理解回溯过程,在本题中如果遇到false,那么就进行上一步的回溯,如果一直没遇到false,就会一直填数字,直到true为止,因此这里也是这题使用bool类型的重要性。