编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
1-9
在每一行只能出现一次。1-9
在每一列只能出现一次。1-9
在每一个以粗实线分隔的 3x3
宫内只能出现一次。(请参考示例图)数独部分空格内已填入了数字,空白格用 '.'
表示。
示例 1:
输入:board = [["5","3",".",".","7",".",".",".","."], ["6",".",".","1","9","5",".",".","."], [".","9","8",".",".",".",".","6","."], ["8",".",".",".","6",".",".",".","3"], ["4",".",".","8",".","3",".",".","1"], ["7",".",".",".","2",".",".",".","6"], [".","6",".",".",".",".","2","8","."], [".",".",".","4","1","9",".",".","5"], [".",".",".",".","8",".",".","7","9"]] 输出: [["5","3","4","6","7","8","9","1","2"], ["6","7","2","1","9","5","3","4","8"], ["1","9","8","3","4","2","5","6","7"], ["8","5","9","7","6","1","4","2","3"], ["4","2","6","8","5","3","7","9","1"], ["7","1","3","9","2","4","8","5","6"], ["9","6","1","5","3","7","2","8","4"], ["2","8","7","4","1","9","6","3","5"], ["3","4","5","2","8","6","1","7","9"]] 解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
本题使用 回溯 (递归)+ 深度遍历算法(dfs) 可较为方便的求解。
1. 首先将board数组转变为数字数组table运算较为简便,等到所有对于矩阵table的运算结束之后再转变成字符数组board。
2. 其次从(x = 0,y = 0)处开始dfs,分别产生以下几种情况:
2.1 当x = 9时,即为第十行,则意味着全部的遍历填数早已结束,则返回True
2.2 当y = 9时,即为每行的第十列,则意味着每行到达了尽头,应该换行了,则递归返回下一行第一个数:dfs(x+1,0)
2.3 当处理后的table[x][y]不为0时,即代表该坐标(x,y)在数独中是初始值,则跳过看下一个位置是否为空:dfs(x,y+1)
2.4 当以上全部的三种情况处理好之后,可以开始填入数据了,则从0~9挨个尝试填入,若当前数val不满足:行唯一、列唯一以及九宫格内唯一这三个条件时,则将当前table[x][y]重置为0,尝试下个数val+1;若三个条件同时满足,既可以填入val并当所有的dfs(x,y+1)成立时,这次填入的所有数全部成立,返回True。
def solveSudoku(self, board):
# tag1将board先转成数字数组方便存放
table = [([0] * 9) for i in range(9)]
# dfs func start……
def dfs(x,y):
# 如果x是第十行(table已全部遍历结束)
if x == 9:
return True
# 如果y是9,则该换行了
if y == 9:
return dfs(x+1,0)
# 如果(x,y)有数字,则跳转到下一个格子
if table[x][y] != 0:
return dfs(x,y+1)
# val代表预计填入0~9的数字
for val in range(10):
# 看是否满足三个条件,有一个不满足标志flag记为false
flag = True
# 行是否唯一
for col in range(9):
if table[x][col] == val:
flag = False
break
# 列是否唯一
for row in range(9):
if table[row][y] == val:
flag = False
break
# (xx,yy)代表每个 3 * 3 方格起点坐标
# 九宫格内是否唯一
xx,yy = x / 3 * 3 , y / 3 * 3
for i in range(3):
for j in range(3):
if table[xx + i][yy + j] == val:
flag = False
break
# 若唯一
if flag == True:
table[x][y] = val #val可填入
if dfs(x,y+1):#全部填入成功
return True
table[x][y] = 0 #当前val填入失败,尝试下一个val
# dfs func end……
# main func start……
for i in range(9):
for j in range(9):
if board[i][j] != '.':
table[i][j] = int(board[i][j])
dfs(0,0)
# tag1将table先转成字符数组board返回
for i in range(9):
for j in range(9):
board[i][j] = str(table[i][j])
# main func end……