37.解数独
做了两天晚上才做出来,主要是回溯忘得差不多了。 第一个问题是怎么终止回溯,用的是函数返回值,如果不为空就表示找到答案,不用继续向下了直接返回就行 第二个注意的思想是每一层函数只进行一个操作(试一个格子),操作完了就进下一层,不要for循环操作多个,就死循环了
class Solution:
def get_candidates(self, board) -> List[Tuple[int, int, List[int]]]:
"""
计算所有空白区域的候选数字
:param board: List,每个元素是个Tuple,分别是row,col和候选数字
如[(1,1,[1,2,3])]表示第一行第一列可以填入1、2、3
:return:
"""
candidates = []
for row in range(9):
for col in range(9):
if board[row][col] != ".":
continue
candidate = []
r, c = row // 3 * 3, col // 3 * 3
cell = [board[r][c], board[r][c + 1], board[r][c + 2],
board[r + 1][c], board[r + 1][c + 1], board[r + 1][c + 2],
board[r + 2][c], board[r + 2][c + 1], board[r + 2][c + 2]]
for test_num in range(1, 10):
if str(test_num) in cell + board[row] + [line[col] for line in board]:
continue
candidate.append(str(test_num))
if candidate:
candidates.append((row, col, candidate))
return list(sorted(candidates, key=lambda candidate: len(candidate[2])))
def solveSudoku(self, board: List[List[str]]) -> Optional[List]:
"""
Do not return anything, modify board in-place instead.
"""
candidates = self.get_candidates(board)
if not candidates: # 没有可以填的数字了,要么是填完了,要么是填错了
for line in board:
if "." in line: # 填错了
return
else: # 填完了
return board
candidate = candidates[0]
for test_num in candidate[2]:
board[candidate[0]][candidate[1]] = test_num
res = self.solveSudoku(board)
if res:
return res
board[candidate[0]][candidate[1]] = "."