力扣题目链接
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 '.' 表示。
解题思路
- 回溯法:数独是一种经典的约束满足问题(CSP),其求解方法通常是回溯法。回溯法的基本思想是尝试为每一个空格填入一个数字,然后递归地尝试填入下一个空格。当遇到冲突(即不能满足数独规则)时,回溯并尝试其他数字。
- 数独规则:在数独中,每个空格需要满足三个条件:
- 在同一行中不重复。
- 在同一列中不重复。
- 在同一个3x3的小方块中不重复。
- 递归与回溯:在每个空格尝试填入1到9的数字,递归地进行填充。如果某个数字不符合条件,则回溯并尝试其他数字。
完整代码如下:
class Solution:def solveSudoku(self, board: List[List[str]]) -> None:"""Do not return anything, modify board in-place instead."""self.backtracking(board)def backtracking(self, board: List[List[str]]) -> bool:# 若有解,返回True;若无解,返回Falsefor i in range(len(board)): # 遍历行for j in range(len(board[0])): # 遍历列# 若空格内已有数字,跳过if board[i][j] != '.': continuefor k in range(1, 10):if self.is_valid(i, j, k, board):board[i][j] = str(k)if self.backtracking(board): return Trueboard[i][j] = '.'# 若数字1-9都不能成功填入空格,返回False无解return Falsereturn True # 有解def is_valid(self, row: int, col: int, val: int, board: List[List[str]]) -> bool:# 判断同一行是否冲突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# 判断同一九宫格是否有冲突start_row = (row // 3) * 3start_col = (col // 3) * 3for i in range(start_row, start_row + 3):for j in range(start_col, start_col + 3):if board[i][j] == str(val):return Falsereturn True
def solveSudoku(self, board: List[List[str]]) -> None:self.backtracking(board)
- 这是主函数,它调用了
backtracking
函数来解决数独。 - 传入的参数
board
是一个二维列表,表示数独的9x9网格。
def backtracking(self, board: List[List[str]]) -> bool:# 若有解,返回True;若无解,返回Falsefor i in range(len(board)): # 遍历行for j in range(len(board[0])): # 遍历列# 若空格内已有数字,跳过if board[i][j] != '.': continuefor k in range(1, 10):if self.is_valid(i, j, k, board):board[i][j] = str(k)if self.backtracking(board): return Trueboard[i][j] = '.'# 若数字1-9都不能成功填入空格,返回False无解return Falsereturn True # 有解
- 遍历整个数独:使用两层循环遍历
board
中的每个位置(i, j)
。如果当前位置不是空的(即不等于'.'
),则跳过。 - 尝试填数字:对于每一个空格,尝试填入数字1到9。
- 调用
is_valid
函数判断数字k
是否可以填入(i, j)
位置。 - 如果可以,则将
board[i][j]
设为k
,然后递归调用backtracking
函数尝试解决下一个空格。 - 如果递归返回
True
,表示找到了一个可行解,则直接返回True
。 - 如果递归返回
False
,则将board[i][j]
重新置为'.'
,表示回溯。
- 调用
- 返回结果:如果遍历了所有位置都找不到一个合法的数字,则返回
False
,表示无解。如果成功填满整个数独,则返回True
。
def is_valid(self, row: int, col: int, val: int, board: List[List[str]]) -> bool:# 判断同一行是否冲突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# 判断同一九宫格是否有冲突start_row = (row // 3) * 3start_col = (col // 3) * 3for i in range(start_row, start_row + 3):for j in range(start_col, start_col + 3):if board[i][j] == str(val):return Falsereturn True
- 行检查:遍历当前行
row
,检查数字val
是否已存在。如果存在则返回False
。 - 列检查:遍历当前列
col
,检查数字val
是否已存在。如果存在则返回False
。 - 3x3方块检查:找到当前空格所属的3x3小方块的起始位置
(start_row, start_col)
,然后检查这个方块内是否存在数字val
。 - 返回结果:如果数字
val
在行、列和3x3方块中都不存在,则返回True
,表示可以在(row, col)
填入数字val
。