题目:https://leetcode-cn.com/problems/sudoku-solver/
代码:
class Solution {
/**
* 空白格
*/
private static final char BLANK = '.';
/**
* 零
*/
private static final char ZERO = '0';
public void solveSudoku(char[][] board) {
this.solve(board, 0, 0);
}
/**
* 从ij位置开始寻找下一个空格的位置,并且尝试填数字
*
* @param board
* @param i
* @param j
* @return
*/
private boolean solve(char[][] board, int i, int j) {
//保存上一次填写数字的位置
int oi = i;
int oj = j;
//计算下一个需要填写数字的位置
while (board[i][j] != BLANK) {
j++;
if (j >= 9) {
//从左往右本行已经到头了,换下一行
i++;
j = 0;
}
if (i >= 9) {
//已经超过总行数,证明数独已经解答出来了
return true;
}
}
//尝试填入1-9的数字
for (int n = 1; n <= 9; n++) {
if (this.isValid(board, i, j, n)) {
//有效,继续填下一位
board[i][j] = (char) (ZERO + n);
if (this.solve(board, i, j)) {
return true;
}
}
}
//1-9都不是正确解,回滚上一位
board[oi][oj] = BLANK;
return false;
}
/**
* 判断填写的数字是否有效
*
* @param board
* @param i
* @param j
* @param n
* @return
*/
private boolean isValid(char[][] board, int i, int j, int n) {
char cn = (char) (ZERO + n);
//通过i和j计算ij所在九宫格第一位的位置
int fi = i - i % 3;
int fj = j - j % 3;
//判断
for (int k = 0; k < 9; k++) {
//行
if (board[i][k] == cn) {
return false;
}
//列
if (board[k][j] == cn) {
return false;
}
//九宫格
if (board[fi + k / 3][fj + k % 3] == cn) {
return false;
}
}
return true;
}
/**
* 打印
*
* @param board
*/
public void print(char[][] board) {
System.out.println(" -----------------------");
for (int i = 0; i < 9; i++) {
System.out.print("| ");
for (int j = 0; j < 9; j++) {
System.out.print(board[i][j] + " ");
if (j % 3 == 2) {
System.out.print("| ");
}
}
if (i % 3 == 2) {
System.out.println("\n -----------------------");
} else {
System.out.println();
}
}
System.out.println();
}
}
为了方便本地调试,上述代码中增加print方法供打印棋盘board,另附赠一个测试用例:
char[][] board = new char[][]{{'5', '3', '.', '.', '7', '.', '.', '.', '.'}, {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, {'.', '.', '.', '.', '8', '.', '.', '7', '9'}};
解题思路:跟51. N 皇后有点类似,也是使用递归+回溯的办法解决。
如图箭头所示,从左往右,从上往下的顺序,寻找每一个空格,并在每一个空格所在位置填入1-9的数字,通过isValid方法判断是否有效,如果有效则填入并继续解答下一个空格,否则继续尝试,都无效的情况下,表达这种情况无解,则回退上一次填入的数字即回溯。
完整的过程参考上方代码,可以本地调试并在需要的位置使用print方法打印出来直观理解。