持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
题目:要求编写一个程序,通过填充空格来解决数独问题。
数独的解法需要满足以下规则:
- 数字
1-9在每行每列只能出现一次。 - 数字
1-9在每个3*3的宫格内只能出现一次。
解题思路
解数独是一个常见的问题,本题并没有最终的结果集合,要求在原数组上修改,那么如果修改了原数组满足条件的话,那原数组对应的值就不能再回溯回去了,因此本题的回溯是有返回值的。
回溯法首先就要寻找返回值,但本题需要遍历数据中所有位置,对所有可填充位置进行填充,当遍历完成即回溯终止,因此不需要终止条件。
每次需要找到数组中可填充位置,之后遍历字符1-9,每次尝试填充,尝试填充需要判断其所在的行列的字符情况,并且需要判断宫格内的元素是否也满足条件,判断是否课填充代码如下:
public boolean isProperSo(char[][] board, int row, int column, char number) {
// 检查列
for (int i = 0; i < 9; i++) {
if (board[row][i] == number) return false;
}
// 检查行
for (int i = 0; i < 9; i++) {
if (board[i][column] == number) return false;
}
// 检查正方形
int startRow = (row / 3) * 3;
int startCol = (column / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) {
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == number) {
return false;
}
}
}
return true;
}
在判断中,如果直接找到了满足条件的位置,此时可以直接终止,无需恢复字符,并且当试完全部元素还是没有返回true,则返回false,如果最终没有返回false,则代表已经找到了正确值,此时可直接返回true。完整代码如下:
public void solveSudoku(char[][] board) {
backtrace(board);
}
public boolean backtrace(char[][] board) {
for (int curRow = 0; curRow < 9; curRow++) {
for (int i = 0; i < board[0].length; i++) {
if (board[curRow][i] != '.') continue;
for (char j = '1'; j <= '9'; j++) {
if (isProperSo(board, curRow, i, j)) {
board[curRow][i] = j;
if(backtrace(board)){
return true;
}
board[curRow][i] = '.';
}
}
return false;
}
}
return true;
}