解数独也是一个典型的回溯算法问题。
首先建立三个数组来记录数独中的行、列和方格中出现过的数字。
然后套用回溯算法的模板,首先处理结束条件,当整个矩阵被遍历完后,返回true值退出回溯过程。当矩阵的当前位置存在数字时,递归调用回溯方法遍历下一个位置,直到遇到矩阵中没有数字的元素时,利用先前建立的三个数组进行判断并剪枝,若最终符合条件,则在当前位置添加新的数字,并继续递归调用回溯方法遍历下一个元素,最后撤回修改操作。
class Solution {
public void solveSudoku(char[][] board) {
//定义三个数组记录行、列和方格中出现过的数字
boolean[][] rowUsed = new boolean[9][10];
boolean[][] colUsed = new boolean[9][10];
boolean[][][] blockUsed = new boolean[3][3][10];
for(int i=0; i<9; i++){
for(int j = 0; j<9; j++){
int num = board[i][j] - '0';
if(num >=1 && num<=9){
rowUsed[i][num] = true;
colUsed[j][num] = true;
blockUsed[i/3][j/3][num] = true;
}
}
}
backtrack(board, rowUsed, colUsed, blockUsed, 0, 0);
}
public boolean backtrack(char[][] board, boolean[][] rowUsed,
boolean[][] colUsed, boolean[][][] blockUsed, int row, int col){
// 边界校验, 如果已经填充完成, 返回true, 表示一切结束
if(col == board[0].length){
col = 0;
row++;
if(row == board.length){
return true;
}
}
// 是空则尝试填充, 否则跳过继续尝试填充下一个位置
if(board[row][col] == '.') {
// 尝试填充1~9
for(int num = 1; num <= 9; num++){
boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || blockUsed[row/3][col/3][num]);
if(canUsed){
rowUsed[row][num] = true;
colUsed[col][num] = true;
blockUsed[row/3][col/3][num] = true;
board[row][col] = (char)('0' + num);
if(backtrack(board, rowUsed, colUsed, blockUsed, row, col + 1)){
return true;
}
board[row][col] = '.';
rowUsed[row][num] = false;
colUsed[col][num] = false;
blockUsed[row/3][col/3][num] = false;
}
}
} else {
return backtrack(board, rowUsed, colUsed, blockUsed, row, col + 1);
}
return false;
}
}