回溯——13.解数独

力扣题目链接

编写一个程序,通过填充空格来解决数独问题。

一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 '.' 表示。

解题思路

  1. 回溯法:数独是一种经典的约束满足问题(CSP),其求解方法通常是回溯法。回溯法的基本思想是尝试为每一个空格填入一个数字,然后递归地尝试填入下一个空格。当遇到冲突(即不能满足数独规则)时,回溯并尝试其他数字。
  2. 数独规则:在数独中,每个空格需要满足三个条件:
    • 在同一行中不重复。
    • 在同一列中不重复。
    • 在同一个3x3的小方块中不重复。
  3. 递归与回溯:在每个空格尝试填入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;若无解,返回False
        for i in range(len(board)): # 遍历行
            for j in range(len(board[0])):  # 遍历列
                # 若空格内已有数字,跳过
                if board[i][j] != '.': continue
                for k in range(1, 10):
                    if self.is_valid(i, j, k, board):
                        board[i][j] = str(k)
                        if self.backtracking(board): return True
                        board[i][j] = '.'
                # 若数字1-9都不能成功填入空格,返回False无解
                return False
        return 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) * 3
        start_col = (col // 3) * 3
        for i in range(start_row, start_row + 3):
            for j in range(start_col, start_col + 3):
                if board[i][j] == str(val):
                    return False
        return True
def solveSudoku(self, board: List[List[str]]) -> None:
    self.backtracking(board)
  • 这是主函数,它调用了 backtracking 函数来解决数独。
  • 传入的参数 board 是一个二维列表,表示数独的9x9网格。
def backtracking(self, board: List[List[str]]) -> bool:
    # 若有解,返回True;若无解,返回False
    for i in range(len(board)):  # 遍历行
        for j in range(len(board[0])):  # 遍历列
            # 若空格内已有数字,跳过
            if board[i][j] != '.': continue
            for k in range(1, 10):
                if self.is_valid(i, j, k, board):
                    board[i][j] = str(k)
                    if self.backtracking(board): return True
                    board[i][j] = '.'
            # 若数字1-9都不能成功填入空格,返回False无解
            return False
    return 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) * 3
    start_col = (col // 3) * 3
    for i in range(start_row, start_row + 3):
        for j in range(start_col, start_col + 3):
            if board[i][j] == str(val):
                return False
    return True
  • 行检查:遍历当前行 row,检查数字 val 是否已存在。如果存在则返回 False
  • 列检查:遍历当前列 col,检查数字 val 是否已存在。如果存在则返回 False
  • 3x3方块检查:找到当前空格所属的3x3小方块的起始位置 (start_row, start_col),然后检查这个方块内是否存在数字 val
  • 返回结果:如果数字 val 在行、列和3x3方块中都不存在,则返回 True,表示可以在 (row, col) 填入数字 val
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值