数独的解法需 遵循如下规则:
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.'
表示。
思路: 类似于N皇后问题,用DFS来解决。
1、放置一个数之前,要先判断一下是否有效(符合规则):
① 数字 1-9
在每一行只能出现一次。
② 数字 1-9
在每一列只能出现一次。
③ 数字 1-9
在每个九宫格只能出现一次。
创建方法:
private boolean isValid(int x, int y, char cur, char[][] board) { // cur 是填充的数字
....
// 其中,怎么判断是哪一个九宫格呢?
// --- 找到九宫格的起始位置即可
// start_x = (x / 3) * 3
// start_y = (y / 3) * 3
}
2、寻找value == '.' 的位置,尝试给他们赋值,不要忘记回溯!
完整代码:
public class Solution {
char[] choose = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
public void solveSudoku(char[][] board) {
int n = board.length;
dfs(board, n, 0 , 0);
}
private boolean dfs(char[][] board, int n, int x, int y) {
if (x == n) {
x = 0;
y++;
if (y == n) {
return true; // 找到解
}
}
if (board[x][y] != '.') {
return dfs(board, n, x + 1, y);
}
for (char num : choose) {
if (isValid(x, y, num, board)) {
board[x][y] = num;
if (dfs(board, n, x + 1, y)) {
return true;
}
board[x][y] = '.'; // 回溯,尝试下一个数字
}
}
return false; // 没有找到解
}
private boolean isValid(int x, int y, char cur, char[][] board) { // cur 是填充的数字
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
if (i == x) {
continue;
}
if (board[i][y] == cur) {
return false;
}
}
for (int j = 0; j < n; j++) {
if (j == y) {
continue;
}
if (board[x][j] == cur) {
return false;
}
}
// 九宫格里只能出现一次
// 先判断在哪个九宫格
int k = (x / 3) * 3;
int l = (y / 3) * 3;
for (int i = k; i < k+3; i++) {
for (int j = l; j < l+3; j++) {
if (i == x && j == y) {
continue;
}
if (board[i][j] == cur) {
return false;
}
}
}
return true;
}
}