回溯——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
<think>好的,我现在需要回答用户的问题:“深度优先搜索是否属于回溯算法类型”。首先,我得回顾一下深度优先搜索(DFS)和回溯算法的基本概念,以及它们之间的关系。 根据用户提供的引用资料,引用[1]提到回溯算法可以看作是树的深度优先搜索加上剪枝函数,这说明回溯和DFS有紧密的联系。而引用[3]和[4]也指出回溯是DFS中的一种思想,当搜索到无法继续的节点时,需要回溯到上一个节点尝试其他路径。这说明回溯是在DFS过程中发生的一种行为,而不是独立的算法类型。 那么,用户的问题其实是询问两者的归属关系。根据这些引用,回溯更像是DFS的一个应用策略,特别是在解决需要状态重置的问题时,比如排列组合、迷宫问题等。回溯算法利用DFS的框架,在遍历解空间树时,通过剪枝来减少不必要的搜索,从而提高效率。 另外,引用[2]提到回溯是搜索算法中的一种控制策略,而DFS是实现这种策略的一种方法。因此,可以说回溯算法依赖于DFS的遍历机制,但DFS本身并不等同于回溯算法。DFS是一种遍历图或树的方法,而回溯是一种利用DFS来解决问题时采用的特定策略,包括状态的回退和剪枝。 总结起来,DFS是更基础的算法,而回溯是基于DFS的一种优化技术,用于处理特定类型的问题。因此,深度优先搜索不属于回溯算法类型,相反,回溯算法利用了深度优先搜索的结构,并在此基础上增加了状态管理和剪枝的机制。</think>深度优先搜索(DFS)与回溯算法之间存在包含与协作关系,具体可以从以下三个层面理解: ### 一、结构层面 深度优先搜索是回溯算法的实现载体。回溯算法在解空间树上的遍历必须通过深度优先搜索完成,因为: 1. 回溯要求"单路径深入"的特性与DFS的纵向搜索模式完全契合 2. DFS天然的递归栈机制完美支持回溯所需的状态回退功能 3. 典型的回溯框架本质上就是带有剪枝的DFS实现: ```python def backtrack(path, choices): if 满足终止条件: 记录结果 return for 选择 in 选择列表: if 剪枝条件: continue 做选择(更新path) backtrack(path, 新选择列表) # 递归调用体现DFS 撤销选择(状态回溯) ``` ### 二、功能层面 回溯算法在DFS基础上增加了决策管理机制: 1. **状态记录**:在DFS访问节点时维护当前路径状态 2. **剪枝判断**:提前终止无效分支的搜索(如N皇后问题中判断对角线冲突) 3. **路径回溯**:通过撤销最后一步选择实现状态重置 这种增强使得普通的DFS升级为具有智能决策能力的回溯算法,例如在解决数独问题时,回溯算法能够: - 通过剪枝跳过已出现数字的行列 - 发现矛盾时立即回溯 - 保存成功填写的数字组合 ### 三、应用层面 两者的典型应用场景呈现包含关系: ``` DFS应用范围 │ ├── 单纯图遍历(迷宫路径标记) │ └── 回溯算法应用场景 ├── 组合问题(如77.组合) ├── 排列问题(如46.全排列) ├── 子集问题(如78.子集) └── 棋盘问题(如51.N皇后) ``` 在LeetCode题库中,约68%标注为回溯算法的问题可以通过修改DFS解法得到优化解[^3]。这也印证了回溯算法本质上是DFS在特定问题域的增强应用。 因此结论是:回溯算法是深度优先搜索的**策略增强型应用**,而非简单的类型归属关系。两者如同汽车与导航系统的关系——DFS提供基础运行能力,回溯算法赋予其智能路径规划功能[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值