Skip to content

Commit 44b10d0

Browse files
aQuaaQua
aQua
authored and
aQua
committed
finish Problem 37
完成了README,重构了程序
1 parent 34db7b2 commit 44b10d0

File tree

3 files changed

+87
-37
lines changed

3 files changed

+87
-37
lines changed

Algorithms/0037.sudoku-solver/README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,16 @@ A sudoku puzzle...
1717

1818
## 解题思路
1919
我把数独框中,需要保证数字不重复的3×3小块,称为一个block。
20-
由于数独需要保持每行,每列,每个block中的数字不重复。
21-
20+
由于数独需要保持每行,每列,每个block中的数字不重复。解题思路如下:
21+
1. 依次往9个block中,分别填写1~9。
22+
1. 如果block中已经存在n了,去填写下一个数。
23+
1. 在可行的空位填好 n 后
24+
1. 如果后面的填写没有问题,返回true
25+
1. 如果后面的填写有问题,把n移入下一个可行的位置。
26+
1. n在这个block中,没有位置放了,返回false
27+
1. 1~9都填写完了,就去填写下一个block分别填写1~9
28+
1. 所有的block都填写完了,结束。
29+
30+
具体过程和细节,见程序及注释。
2231
## 总结
23-
24-
32+
虽然,我一直主张编写不超过20行的函数,但是匿名函数确实好用。
Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,72 @@
11
package Problem0037
22

33
func solveSudoku(board [][]byte) {
4-
nums := []byte("123456789")
5-
blocks := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
6-
7-
if !fillBlock(board, nums, blocks) {
4+
if !fill(board, '1', 0) {
85
panic("此题无解")
96
}
107
}
118

12-
func fillBlock(board [][]byte, nums []byte, blocks []int) bool {
13-
if len(blocks) == 0 {
9+
func fill(board [][]byte, n byte, block int) bool {
10+
if block == 9 {
11+
// 所有的block都已经填满,成功找到了解
1412
return true
1513
}
16-
if len(nums) == 0 {
17-
return fillBlock(board, []byte("123456789"), blocks[1:])
18-
}
1914

20-
block := blocks[0]
21-
n := nums[0]
22-
nums = nums[1:]
15+
if n == '9'+1 {
16+
// 此 block 已经被填满了,去填写下一个 block
17+
return fill(board, '1', block+1)
18+
}
2319

2420
// print(board, n, block)
2521

26-
rowZero := (block / 3) * 3
27-
colZero := (block % 3) * 3
22+
rowBegin := (block / 3) * 3
23+
colBegin := (block % 3) * 3
2824

29-
// 检查block中,是否已经存在 b 了
30-
had := func() bool {
31-
for r := rowZero; r < rowZero+3; r++ {
32-
for c := colZero; c < colZero+3; c++ {
33-
if board[r][c] == n {
34-
return true
35-
}
25+
for r := rowBegin; r < rowBegin+3; r++ {
26+
for c := colBegin; c < colBegin+3; c++ {
27+
if board[r][c] == n {
28+
// block 中已经有 n 了,无需填写
29+
// 去填写下一个 n
30+
return fill(board, n+1, block)
3631
}
3732
}
38-
return false
3933
}
4034

41-
if had() {
42-
return fillBlock(board, nums, blocks)
43-
}
44-
// 检查(r,c)所在的行和列是否已经存在 n 了
45-
isClear := func(r, c int) bool {
35+
// 检查 (r,c) 能否存放 n
36+
// 使用匿名函数,避免传递参数
37+
isAvaliable := func(r, c int) bool {
38+
// 当前位置上的字符需为 '.'
39+
if board[r][c] != '.' {
40+
return false
41+
}
42+
43+
// (r,c) 所在的行和列不能有 n
44+
// 在这里就可以体现,挨个往block中填写的优势了。
4645
for i := 0; i < 9; i++ {
4746
if board[r][i] == n || board[i][c] == n {
4847
return false
4948
}
5049
}
50+
5151
return true
5252
}
5353

54-
for r := rowZero; r < rowZero+3; r++ {
55-
for c := colZero; c < colZero+3; c++ {
56-
if board[r][c] == '.' && isClear(r, c) {
54+
for r := rowBegin; r < rowBegin+3; r++ {
55+
for c := colBegin; c < colBegin+3; c++ {
56+
if isAvaliable(r, c) {
5757
board[r][c] = n
58-
if fillBlock(board, nums, blocks) {
58+
if fill(board, n+1, block) {
5959
return true
6060
}
61-
// 后面的填写不成功,所以需要还原这个格子
61+
62+
// 把 (r,c) 还原,把 n 移入下一个可行的位置
6263
board[r][c] = '.'
64+
6365
// print(board, n, block)
6466
}
6567
}
6668
}
67-
69+
// n 在此 block 中无处可放。
70+
// 返回 false ,让前一个 n 调整位置。
6871
return false
6972
}

Algorithms/0037.sudoku-solver/sudoku-solver_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,45 @@ func Test_Problem0036(t *testing.T) {
6464
ast.Equal(a.one, p.one, "输入:%v", p)
6565
}
6666
}
67+
func Test_Panic(t *testing.T) {
68+
ast := assert.New(t)
69+
70+
qs := []question{
71+
72+
question{
73+
para{[][]byte{
74+
[]byte("..9748..."),
75+
[]byte("7....8..."),
76+
[]byte(".2.1.9..."),
77+
[]byte("..7...24."),
78+
[]byte(".64.1.59."),
79+
[]byte(".98...3.."),
80+
[]byte("...8.3.2."),
81+
[]byte("........6"),
82+
[]byte("...2759.."),
83+
}},
84+
ans{[][]byte{
85+
[]byte("519748632"),
86+
[]byte("783652419"),
87+
[]byte("426139875"),
88+
[]byte("357986241"),
89+
[]byte("264317598"),
90+
[]byte("198524367"),
91+
[]byte("975863124"),
92+
[]byte("832491756"),
93+
[]byte("641275983"),
94+
}},
95+
},
96+
97+
// 如需多个测试,可以复制上方元素。
98+
}
99+
100+
for _, q := range qs {
101+
p := q.para
102+
fmt.Printf("~~%v~~\n", p)
103+
ast.Panics(func() { solveSudoku(p.one) }, "输入:%v", p)
104+
}
105+
}
67106

68107
func print(board [][]byte, b byte, block int) {
69108
fmt.Printf("\n====fill %d in block %d ====", b-'0', block)

0 commit comments

Comments
 (0)