数据结构与算法 -第 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
相关推荐
深圳市快瞳科技有限公司5 小时前
野外鸟类AI识别落地实录:输入适配、结构化输出、去重聚合与置信度分流的工程实践
算法·计算机视觉·鸟类识别·鸟类ai识别·野外鸟类观测·林业调查
叼烟扛炮5 小时前
Linux 学习笔记(四十一):TCP 并发演进——从单进程到多线程服务器
linux·运维·服务器·网络·笔记·学习·tcp/ip
叼烟扛炮5 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
songyuc6 小时前
【Manskill3】TableSceneBuilder学习笔记
pytorch·笔记·学习
专注仿真6 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
小豆庄6 小时前
视频遮罩追踪退场后ID撞号的排查—多目标场景下的失效
opencv·算法·bug·视频·python3.11
外收内放6 小时前
Python基础语法练习题(75)
开发语言·python·学习
Tisfy7 小时前
LeetCode 3882.网格图中最小异或路径:动态规划
算法·leetcode·动态规划
黑十8 小时前
PyTorch 报 “no CUDA GPUs are available“ 怎么办?3 步排查
服务器·网络·人工智能·pytorch·python
D e re k ZH8 小时前
P5025 [SNOI2017] 炸弹
c++·算法