LeetCode 链接:37. 解数独
题目描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
填充完成后的数独板如下:
代码实现
class ShuduSolver:
"""
编写一个程序,通过填充空格来解决数独问题。
https://leetcode.cn/problems/sudoku-solver/
"""
def solution(self, board: List[List[str]]):
row = [[False]*10 for _ in range(9)]
col = [[False]*10 for _ in range(9)]
bucket = [[False]*10 for _ in range(9)]
self.initMaps(board, row, col, bucket)
self.process(board, 0, 0, row, col, bucket)
def initMaps(self, board, row, col, bucket):
"""
:param board:
:param row: row[i][num] 表示第i行 num这个数 是否出现过
:param col: col[j][num] 表示第j列 num这个数 是否出现过
:param bucket: bucket[bid][num] 表示第bid号桶 num这个数 是否出现过
:return:
"""
for i in range(9):
for j in range(9):
# bucket 编号
bid = 3*(i//3) + j//3
if board[i][j] != '.':
num = int(board[i][j])
row[i][num] = True
col[j][num] = True
bucket[bid][num] = True
def process(self, board, i, j, row, col, bucket):
"""
对单个位置 深度优先遍历
当前来到(i,j)这个位置,如果已经有数字,跳到下一个位置上;
如果没有数字,尝试1~9,不能和row、col、bucket冲突
:param board:
:param i:
:param j:
:param row:
:param col:
:param bucket:
:return:
"""
# 已经遍历完9行了
if i == 9:
return True
# 当离开(i,j),应该去哪?(nexti, nextj)
next_i = i if j != 8 else i + 1
next_j = j+1 if j != 8 else 0
if board[i][j] != '.':
return self.process(board, next_i, next_j, row, col, bucket)
else:
# 可以尝试1~9
bid = 3*(i//3) + j//3
for num in range(1, 10):
if not row[i][num] and not col[j][num] and not bucket[bid][num]:
# 可以尝试num
row[i][num] = True
col[j][num] = True
bucket[bid][num] = True
board[i][j] = str(num)
if self.process(board, next_i, next_j, row, col, bucket):
return True
# 还原
row[i][num] = False
col[j][num] = False
bucket[bid][num] = False
board[i][j] = '.'
return False