echo

任生命穿梭 时间的角落

0%

解数独

37. 解数独

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

空白格用 '.' 表示。

image-20200915085345737

一个数独。

image-20200915085359798

答案被标成红色。

Note:

  • 给定的数独序列只包含数字 1-9 和字符 '.'
  • 你可以假设给定的数独只有唯一解。
  • 给定数独永远是 9x9 形式的。

由于每个数字只能在同一行、同一列和同一个九宫格中只会出现一次,我们使用三个数组来标记该数字是否出现,如果出现则直接退出递归。同时使用一个数组保存剩余的空位,对每个空位尝试放入 1- 9的数字,如果将所有空位都使用完,没有出现错误则发现了一种解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution {
private boolean[][] line = new boolean[9][9];
private boolean[][] column = new boolean[9][9];
private boolean[][][] block = new boolean[3][3][9];
private boolean valid = false;
private List<int[]> spaces = new ArrayList<int[]>();

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;
line[i][digit] = column[j][digit] = block[i / 3][j / 3][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];
//尝试将该空位中放入 1-9
for(int digit = 0; digit < 9 && !valid; ++digit){
if(!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]){
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;
board[i][j] = (char) (digit + '0' + 1);
dfs(board, pos + 1);
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false;
}
}
}
}