数据结构与算法 -第 3 章 常用算法-回溯算法

第 3 章 常用算法

3.5 回溯算法

3.5.1 概述

回溯算法是一种通过探索所有可能的解来解决问题的算法。回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现,现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用递归方法来实现。

回溯算法的基本步骤可以总结为:

  • 选择:在每个决策点选择一个候选解。

  • 探索:递归地继续在下一个决策点上做选择。

  • 验证:在每次选择之后,检查当前路径是否满足条件。

  • 回溯:当某条路径不满足条件或无法继续时,回到上一步,尝试其他可能的选择。

3.5.2 案例一:全排列

力扣46题https://leetcode.cn/problems/permutations/description/

现有一个不含重复数字的数组nums ,返回其所有可能的全排列。

示例:

  • 输入:nums = 1,2,3

  • 输出:\[1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1]

1)思路分析

实现步骤:

  • 选择:从待排列的元素中选择一个元素作为当前位置的元素。

  • 递归:将该元素固定在当前位置后,递归排列下一个元素。

  • 终止条件:所有位置的元素都已确定,添加到结果中并终止递归。

  • 回溯:回到上一步,撤销当前的选择,尝试下一个可能的元素。

Python 复制代码
def permute(nums):
    result = []
 
    def backtrack(start):
        # 到达末尾,将此时排列结果添加到最终结果中
        if start == len(nums):
            result.append(nums[:])
            return
 
        for i in range(start, len(nums)):
            # 选取当前位置的元素:将要选取的元素与此位置的元素互换
            if start != i:
                nums[start], nums[i] = nums[i], nums[start]
            # 递归处理下一个位置的元素
            backtrack(start + 1)
            # 回溯,恢复原始数组
            if start != i:
                nums[start], nums[i] = nums[i], nums[start]
 
    backtrack(0)
    return result

3.5.3 案例二:N皇后

力扣51题https://leetcode.cn/problems/n-queens/description/

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n皇后问题研究的是如何将n个皇后放置在n×n的棋盘上,并且使皇后彼此之间不能相互攻击。给一个整数n,返回所有的解决方案。每一个方案中 'Q' 和 '.' 分别代表了皇后和空位。

  • 输入:n = 4

  • 输出:\[".Q..","...Q","Q...","..Q.","..Q.","Q...","...Q",".Q.."]

解释:如上图所示,4皇后问题存在两个不同的解法。

1)思路分析

实现步骤:

  • 选择:从棋盘每行中选择一个列放置棋子。

  • 验证合法性:每次放置一个皇后时,检查该位置是否与其他已经放置的皇后在列或对角线上发生冲突。

  • 递归:棋子放置位置合法则递归放置下一个棋子。

  • 终止条件:若所有棋子都放置完则终止递归。

  • 回溯:回到上一步,尝试下一个位置。

Python 复制代码
def n_queens(n):
    result = []
    cols = set()  # 记录哪些列有皇后
    diag1 = set()  # 记录哪些主对角线上有皇后
    diag2 = set()  # 记录哪些副对角线上有皇后
 
    # 初始化棋盘
    board = [["." for _ in range(n)] for _ in range(n)]
 
    def backtrack(row):
        # 如果已经放置了n个皇后,说明找到一个解
        if row == n:
            result.append(["".join(row) for row in board])
            return
 
        for col in range(n):
            # 检查当前列和对角线是否有皇后
            if col in cols or (row - col) in diag1 or (row + col) in diag2:
                continue  # 如果有冲突,跳过当前列
 
            # 放置皇后
            board[row][col] = "Q"
            # 标记当前列和对角线
            cols.add(col)
            diag1.add(row - col)
            diag2.add(row + col)
 
            # 递归处理下一行
            backtrack(row + 1)
 
            # 回溯,删除当前位置的皇后,并清理列和对角线的标记
            board[row][col] = "."
            cols.remove(col)
            diag1.remove(row - col)
            diag2.remove(row + col)
 
    backtrack(0)
return result
相关推荐
零基础1231 小时前
LLM4AD:面向算法设计的大语言模型智能体框架
人工智能·算法·语言模型
计算机编程指导师1 小时前
Python毕设怎么做?基于hadoop的商家优惠券营销效果数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·spark·毕业设计·课程设计·优惠券
计算机编程指导师1 小时前
【Python毕设推荐】基于Hadoop+Spark的商场商铺运行数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·spark·课程设计·商场商铺
haluhalu.1 小时前
Agent = LLM + 上下文 + 工具(含观察 / 动作空间、ReAct 循环)
前端·javascript·人工智能·python·react.js·机器学习·个人开发
mldong1 小时前
给 Django Admin 加审批流:一行前端代码没写,298 行接上工作流引擎
后端·python·架构
kobe_OKOK_8 小时前
__getattr__和__getattribute__如何用
python
全栈弄潮儿9 小时前
Python实战第2期: 变量与数据类型
后端·python·agent
长沙三为智能科技10 小时前
家政小程序门店运营模块设计:会员、下单、派单、结算四段链路的落地拆解
python·小程序·内容运营
Cc.Y10 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python