描述
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
一个数独。
答案被标成红色。
提示:
- 给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
- 你可以假设给定的数独只有唯一解。
- 给定数独永远是 9x9 形式的。
思路
- 这道题做了一天没解出来…哎,好难,最终还是看了答案。
- 解数独是回溯算法的经典应用。这道题要注意题设一点:答案唯一。也就是说,回溯时只要找到一个答案,程序就可以结束了。为了达到此目的,将回溯函数返回值设为bool,当找到答案时返回true,不再继续递归。
- 从第0行0列开始遍历,先遍历第0行的每一列,然后遍历第1行的每一列…如此直到row=9时超出网格范围,递归结束。
- 对于某些网格,如果为空,才从1~9开始遍历往里填,如果已经有值了,那么直接跳过此格子,进入本行的下一个格子。
- 需要写一个函数,判断当前格子的同行、同列,本宫(3x3格子)内是否已经有此元素,没有才能放,有的话跳过。
解答
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
backTrack(board, 0, 0);//从第0行0列开始递归
}
bool backTrack(vector<vector<char>>& board, int row, int column){
if(row == 9) return true;//row=9说明找到了正确结果
if(column == 9)
return backTrack(board, row + 1, 0);//column=9,则开始下一行,必须return,否则下面代码还会执行
if(board[row][column] == '.'){
for(char i = '1';i <= '9'; ++ i){
if(isInBoard(board, row, column, i) == false){//当前数可填入
board[row][column] = i;
if(backTrack(board, row, column + 1)) return true;//找到结果,结束程序
board[row][column] = '.';
}
}
}else{
//本层得到后续递归的结果抛给上一层,不return会执行下面的return false,将false抛给上层
return backTrack(board, row, column + 1);
}
return false;//能执行到这步,说明遍历完1~9也没找到合适的数,则失败。
}
//查找某个数是否已经在本行、本列、本宫内存在,已存在则返回true
bool isInBoard(vector<vector<char>>& board, int row, int column, char target){
for(int k = 0;k < 9; ++ k){
if(board[row][k] == target || board[k][column] == target ||
board[(row / 3) * 3 + k / 3][(column / 3) * 3 + k % 3] == target)
return true;
}
return false;
}
};