37.解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例:
分析:
回溯法解决
我们可以考虑按照行优先的顺序依次枚举每一个空白格中填的数字,通过递归+回溯的方法枚举所有可能的填法。如果填到最后一个格子,仍没有冲突则说明我们已经找到答案了
数独条件:
每个数在每一行每一列每一个块都只能出现一次
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
# 先初始化行,列,块以列表嵌套集合的方式,且每行每列每块都初始化为1到9的集合
row = [set(range(1,10)) for _ in range(9)]
col = [set(range(1,10)) for _ in range(9)]
block = [set(range(1,10)) for _ in range(9)]
empty = [] # 记录空格子的位置
# 遍历寻找有数字的格子和空格子
for i in range(9):
for j in range(9):
if board[i][j] != '.':
val = int(board[i][j]) # 数据类型转换
row[i].remove(val) # 如果该数字在这一行这一列这一块存在则把该值移除
col[j].remove(val)
block[i // 3 * 3 + j // 3].remove(val)
else:
empty.append((i,j)) # 记录空格子位置
def backtrack(iter = 0): # 回溯填值
if iter == len(empty): # 终止条件
return True
i, j = empty[iter] # 读出每个空格子的位置
b = i // 3 * 3 + j // 3 # 下标与块的关系
for val in row[i] & col[j] & block[b]: # 如果一个值在行列块中都存在在进行填值操作,并做相应的移除操作
row[i].remove(val)
col[j].remove(val)
block[b].remove(val)
board[i][j] = str(val) # 注意类型转换
if backtrack(iter+1): # dill down,
return True
# 否则恢复到之前状态
row[i].add(val)
col[j].add(val)
block[b].add(val)
# 未找到解返回False
return False
backtrack()
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
def backtrack(board):
for i in range(len(board)): #遍历行
for j in range(len(board[0])): #遍历列
if board[i][j] != ".": continue
for k in range(1,10): #(i, j) 这个位置放k是否合适
if isValid(i,j,k,board):
board[i][j] = str(k) #放置k
if backtrack(board): return True #如果找到合适一组立刻返回
board[i][j] = "." #回溯,撤销k
return False #9个数都试完了,都不行,那么就返回false
return True #遍历完没有返回false,说明找到了合适棋盘位置了
def isValid(row,col,val,board):
for i in range(9): #判断行里是否重复
if board[row][i] == str(val):
return False
for j in range(9): #判断列里是否重复
if board[j][col] == str(val):
return False
startRow = (row // 3) * 3
startcol = (col // 3) * 3
for i in range(startRow,startRow + 3): #判断9方格里是否重复
for j in range(startcol,startcol + 3):
if board[i][j] == str(val):
return False
return True
backtrack(board)