描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
分析
遍历数组找到待填写的空白,用1~9尝试,写入符合条件的字符,然后进入下一轮递归填写下一个空白。直到双层for循环跳出循环,说明每个空白都找到了合适的数值,返回true,结束递归,不停的向上返回true,整个回溯也就结束。
- 两层for是为了方便找到当前需要待填写的空白
- 与常见的回溯相比多了返回值,借助返回值来判断是否需要恢复现场。返回值是true,只有一种情况才会返回true,就是填写完了所有的空白,找到了最终解。若返回值是false,说明下层的递归不满足条件,需要恢复现场。
- 整数转字符,不能靠加单引号来转变,比如下面代码是错的,'k’指的就是字符k,不会把k看作变量。
for(int k = 1; k <= 9; k++){
if(isAvailable(board,i,j,'k')){
board[i][j] = 'k';
if(backTracking(board)) {
return true;
}
board[i][j] = '.';
}
}
class Solution {
public void solveSudoku(char[][] board) {
backTracking(board);
}
public boolean backTracking(char[][] board){
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j] != '.'){
continue;
}
for(int k = 1; k <= 9; k++){
if(isAvailable(board,i,j,'k')){
board[i][j] = 'k';
if(backTracking(board)) {
return true;
}
board[i][j] = '.';
}
}
return false;
}
}
return true;
}
public boolean isAvailable(char[][] board, int row, int col, char k){
for(int i = 0; i < board.length; i++){
if(board[row][i] == k){
return false;
}
}
for(int i = 0; i < board.length; i++){
if(board[i][col] == k){
return false;
}
}
int rowStart = (row/3)*3;
int colStart = (col/3)*3;
for(int i = rowStart; i < rowStart+3; i++){
for(int j = colStart; j < colStart+3; j++){
if(board[i][j] == k){
return false;
}
}
}
return true;
}
}