0%

LeetCode.37.解数独(困难)

题目

LeetCode.37.解数独(困难)

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

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

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

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

题解

从左到右从上到下遍历所有没有填空的位置,尝试去填数字;填过的位置就跳过。

填过的数字就不能再用了,但是不知道填哪个数字,所以要尝试所有的可能性,采用暴力回溯解法。

填数字时要有三个限制条件,都是保证数字不重复,那么就要存储已访问过的数字,按行、按列、按3x3宫格分开记录和判断,这样最方便快速。

如果能按照限制条件填满一种可能性,就不用再尝试其他可能性了,直接结束程序。

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
45
46
47
48
class Solution {
fun solveSudoku(board: Array<CharArray>) {
if (board.isEmpty()) return
val n = board.size
val rowUsed = Array(n) { BooleanArray(n + 1) { false } }
val columnUsed = Array(n) { BooleanArray(n + 1) { false } }
val boxUsed = Array(3) { Array(3) { BooleanArray(n + 1) { false } } }
for (i in 0 until n) {
for (j in 0 until n) {
if (board[i][j] in '1'..'9') {
val num = board[i][j] - '0'
rowUsed[i][num] = true
columnUsed[j][num] = true
boxUsed[i / 3][j / 3][num] = true
}
}
}
fun dfs(row: Int, column: Int): Boolean {
var r = row
var c = column
if (c == n) {
c = 0
r++
if (r == n) return true
}
if (board[r][c] == '.') {
for (i in 1..9) {
if (rowUsed[r][i] || columnUsed[c][i] || boxUsed[r / 3][c / 3][i]) continue
board[r][c] = i.toString()[0]
rowUsed[r][i] = true
columnUsed[c][i] = true
boxUsed[r / 3][c / 3][i] = true
if (dfs(r, c + 1)) {
return true
}
board[r][c] = '.'
rowUsed[r][i] = false
columnUsed[c][i] = false
boxUsed[r / 3][c / 3][i] = false
}
return false
} else {
return dfs(r, c + 1)
}
}
dfs(0, 0)
}
}