这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
前言
力扣第三十七题 解数独 如下所示:
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9在每一行只能出现一次。 - 数字
1-9在每一列只能出现一次。 - 数字
1-9在每一个以粗实线分隔的3x3宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
示例:
一、思路
解数独就是通过不断在空格中填数字,直到满足调节的结果出现。 这个过程就是不断的往空格中填入数字,直到填完所有的数字且能满足三个条件,就是找到了解。
填写的步骤大致如下所示:
- 找到所有的空格
- 使用递归依次向空格中填入值,如果不能满足则向上回溯
- 直到出现结果为止
举个例子
此处以示例中的数独作为例子,如下所示:
因为是横向扫描的,所以 0, 2 是第一个空格的位置,我们从 1~9 依次向其中填入。如果满足条件就继续填下一个位置。
刚好第一个 0, 2 空格可以满足条件,故填上 1
继续往下填写后,会有下面这个结果。你会发现 0, 8 这个位置此时没有满足的值了。(不能填6,因为同一列中已经有一个6了)
所以此时向上回溯到 0, 7 这个位置,你会发现 0, 7 这个位置也是填不了 6 的,因为列中也有一个 6 了。
所以会继续向上回溯
......,经过不停的探索,最终会得到下面这个结果:
举个例子
二、实现
实现代码
实现代码与思路中保持一致,命名等可见注释
private boolean[][] rowRecords = new boolean[9][9]; // 行
private boolean[][] colRecords = new boolean[9][9]; // 列
private boolean[][] subBoxRecords = new boolean[9][9]; // 子盒子记录
private boolean valid = false; // 满足条件
private List<int[]> spaces = new ArrayList<>(); // 空格的位置
public void solveSudoku(char[][] board) {
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') {
spaces.add(new int[]{i, j});
} else {
int digit = board[i][j] - '0' - 1;
// 子盒子下标
int boxIndex = i/3 + j/3*3;
rowRecords[i][digit] = colRecords[j][digit] = subBoxRecords[boxIndex][digit] = true;
}
}
}
dfs(board, 0);
}
/**
* 递归
*/
public void dfs(char[][] board, int pos) {
// 满足条件直接返回
if (pos == spaces.size()) {
valid = true;
return;
}
int[] space = spaces.get(pos);
int i = space[0], j = space[1];
for (int digit = 0; digit < 9 && !valid; ++digit) {
// 子盒子下标
int boxIndex = i/3 + j/3*3;
// 确保行、列及子盒子都可以填
if (!rowRecords[i][digit] && !colRecords[j][digit] && !subBoxRecords[boxIndex][digit]) {
rowRecords[i][digit] = colRecords[j][digit] = subBoxRecords[boxIndex][digit] = true;
board[i][j] = (char) (digit + '0' + 1);
dfs(board, pos + 1);
rowRecords[i][digit] = colRecords[j][digit] = subBoxRecords[boxIndex][digit] = false;
}
}
}
测试代码
public static void main(String[] args) {
char[][] board =
{{'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'}};
new Number37().solveSudoku(board);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥