Java 求解-解数独
Posted 南淮北安
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 求解-解数独相关的知识,希望对你有一定的参考价值。
一、题目
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
二、题解
N皇后问题是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来来遍历列,然后一行一列确定皇后的唯一位置。
本题就不一样了,「本题中棋盘的每一个位置都要放一个数字,并检查数字是否合法,解数独的树形结构要比N皇后更宽更深」。
因为这个树形结构太大了,我抽取一部分,如图所示:
(1)确定递归函数以及参数
因为解数独找到一个符合的条件(就在树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值
所以,递归函数的返回值需要是 bool 类型
boolean backTracking(char[][] board)
(2)确定递归终止条件
本题递归不用终止条件,解数独是要遍历整个树形结构寻找可能的叶子节点就立刻返回。
递归的下一层的棋盘一定比上一层的棋盘多一个数,等数填满了棋盘自然就终止(填满当然好了,说明找到结果了),所以不需要终止条件!
(3)确定单层搜索逻辑
在树形图中可以看出我们需要的是一个二维递归(也就是两个for循环嵌套着递归)
「一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!」
三、代码
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.length; j++) {
// 开始存放数字
if (board[i][j] == '.') {
// 找到一个合适的数字
for (char ch = '1'; ch <= '9'; ch++) {
// 判断该数字是否合规
if (isValid(board, i, j, ch)) {
board[i][j] = ch;
// 找到一组合适的,立即返回
if (backTracking(board)) {
return true;
}
// 回溯
board[i][j] = '.';
}
}
// 9个数字都试完了,都不是合适,返回 FALSE
return false;
}
}
}
// 遍历完,没有返回 FALSE,说明找到了合适的排列
return true;
}
// 判断当前位置是否可以存放 ch
public boolean isValid(char[][] board, int row, int col, char ch) {
// 判断当前行,当前列,是否已经存在 ch
for (int i = 0; i < board.length; i++) {
if (board[row][i] == ch || board[i][col] == ch) {
return false;
}
}
// 处理九宫格是否存在 ch
row = (row / 3) * 3;
col = (col / 3) * 3;
for (int i = row; i < row + 3; i++) {
for (int j = col; j < col + 3; j++) {
if (board[i][j] == ch) {
return false;
}
}
}
return true;
}
}
四、总结
该题,相对前面的回溯题目,是比较复杂的
大部分的回溯题目都是一维递归,该题涉及到了二维递归
需要考虑处理的情况比较复杂,因为每一个位置的情况都要考虑
可以注意下,对于九宫格判断是否合规的处理:
// 处理九宫格是否存在 ch
row = (row / 3) * 3;
col = (col / 3) * 3;
for (int i = row; i < row + 3; i++) {
for (int j = col; j < col + 3; j++) {
if (board[i][j] == ch) {
return false;
}
}
}
这样处理,限制了九宫格每次的取值是0-3,4-6,7-9
以上是关于Java 求解-解数独的主要内容,如果未能解决你的问题,请参考以下文章