问题描述
解题思路
看到这个题,给我的感觉是什么玩意啊!仔细读题之后,真的没想到解题思路。然后看了题解,用到了回溯算法,感觉这个回溯和N皇后的问题差不太多。然后就照着思路尝试理解了一遍,感觉这种题目前针对我来讲的话,确实算是困难的题目。看来还是要学学回溯算法。思路根据代码理解。整体思路如下。
在 dfs 方法中,pos 表示当前处理的位置。如果 pos 等于 spaces 的长度,说明所有空格都已经填充完毕,将 valid 标记为 True 并返回。
获取当前空格的坐标 (i, j),然后尝试填充数字。对于每个数字(0 到 8),检查该数字是否可以填充到当前位置。如果满足条件,则标记该数字已被使用,更新数独表格,并继续下一个空格的填充。
在递归填充下一个空格之前,需要将之前的标记复原,以便在不同的分支中尝试不同的数字。
如果 valid 已经为 True,则表示已找到解,直接返回。
初始化 line、column 和 block 三个二维数组,用于记录每行、每列和每个 3x3 的块中数字的使用情况。
将数独表格中已有的数字标记为已使用,并将空格的坐标保存到 spaces 列表中。
调用 dfs(0) 开始填充数独表格。
通过深度优先搜索的方式尝试填充数独表格,同时通过回溯的方式处理不合法的填充,直到找到合法的解或者遍历完所有可能的情况。
代码如下
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
def dfs(pos: int):
nonlocal valid
if pos == len(spaces):
valid = True
return
i, j = spaces[pos]
for digit in range(9):
if line[i][digit] == column[j][digit] == block[i // 3][j // 3][digit] == False:
line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = True
board[i][j] = str(digit + 1)
dfs(pos + 1)
line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = False
if valid:
return
line = [[False] * 9 for _ in range(9)]
column = [[False] * 9 for _ in range(9)]
block = [[[False] * 9 for _a in range(3)] for _b in range(3)]
valid = False
spaces = list()
for i in range(9):
for j in range(9):
if board[i][j] == ".":
spaces.append((i, j))
else:
digit = int(board[i][j]) - 1
line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = True
dfs(0)