刷题总结 回溯算法

为了方便复习并且在把算法忘掉的时候能尽量快速的捡起来

刷完回溯算法这里需要做个总结

回溯算法的适用范围

回溯算法是深度优先搜索(DFS)的一种特定应用,在DFS的基础上引入了约束检查回退机制

相比于普通的DFS,回溯法的优势主要体现在解决需要约束条件判断、剪枝回退的复杂问题上。

实际应用时有易于识别的题目类型特征组合、分割、子集、排列、棋盘

这些问题的共同点是解空间均为层次结构,因此回溯算法就是对回溯树进行DFS

模式识别

根据自己刷题的感受,并统计做题过程中思路上遇到过的槛,

归纳后可以得到以下模式识别树,

专门用于看到题目后进行模式识别,

快速找到解题方法:

该模式识别树综合搜索集类型、搜索规则和结果收集条件等因素

接下来对当前的模式识别树进行简单解释:

回溯算法总模板:

def backtracking(self, 参数):
    if 终止条件
        存放结果
        return

    for 选择:本层集合中元素(树中节点孩子的数量就是集合的大小):
        处理节点
        self.backtracking(路径,选择列表) // 递归
        回溯,撤销处理结果

步骤:1.函数(无返回值,参数多) + 2.if(终止){收集+return} + 3.for(搜索集){处理;递归;回溯}

回溯树:

一、题目类型

回溯算法常用于解决问题:组合、分割、子集、排列、棋盘等

在我眼里以上题目类型可以总结为三个大类:组合类问题、排列类问题和约束满足类问题,

因此,这几个大类是根据解空间(回溯树)的层次结构进行划分的,

而且对模板的应用有较大的影响

1.组合类问题:层内层间顺序访问

包含类型:组合、分割、子集

模板变体:

def backtracking(self, 输入参数, start_idx, path, ans):
    if 终止条件
        存放结果
        return

    for i in range(start_idx, len(总搜索集)):
        if 约束条件:
            continue # 有时需要break
        处理节点
        self.backtracking(输入参数, start_idx + 1, path, ans) // 递归
        回溯,撤销处理结果

def backtracking(self, 输入参数, start_idx, path, ans):
    if 终止条件
        存放结果
        return

    for i in range(start_idx, len(总搜索集)):
        if 约束条件:
            处理节点
            self.backtracking(输入参数, start_idx + 1, path, ans) // 递归
            回溯,撤销处理结果

模式识别特征:

  • 不考虑顺序

  • 一般搜索集长度大于结果长度

  • 回溯树层内层间顺序访问

题目列表:

组合

77. 组合

216. 组合总和 III

39. 组合总和

40. 组合总和 II

分割

131. 分割回文串

93. 复原 IP 地址

子集

78. 子集

90. 子集 II

491. 非递减子序列

这其中有一个特例就是重复选取题:39. 组合总和

递归命令需要改为:

# self.backtracking(输入参数, start_idx + 1, path, ans) // 递归
self.backtracking(输入参数, start_idx, path, ans) // 递归

2.排列类问题:层内遍历访问层间顺序访问

包含类型:排列

模板变体:

该类型题目有visited数组写法、集合写法和交换元素三种写法,

visited数组普适性较强,以visited数组写法为例:

def backtracking(self, 输入参数, visited, path, ans):
    if 终止条件
        存放结果
        return

    for i in range(len(总搜索集)):
        if visited[i] or 其他约束条件:
            continue
        处理节点
        visited[i] = True
        self.backtracking(输入参数, visited, path, ans) // 递归
        visited[i] = False
        其他回溯,撤销处理结果

模式识别特征:

  • 考虑顺序

  • 搜索集长度等于结果长度

  • 回溯树层内遍历,层间顺序访问

题目列表:

46. 全排列

47. 全排列 II

3.约束满足问题:约束条件较强,无特定访问顺序

包含类型:安排行程、棋盘

相比于总模板无特定要求,但常需要主函数预处理搜索集以剪枝回溯树,实现高效搜索

模式识别特征:

  • 一般类似于排列问题

  • 有较强的约束条件

  • 一般需要对搜索集预处理,否则会超时或代码过于复杂

题目列表:

332. 重新安排行程

棋盘

51. N 皇后

37. 解数独

二、几个需要注意的题目类型的约束条件

这个只有一个维度,目前共遇到三个种类:

1.组合:结果收集条件和剪枝优化

1.1 长度

用长度作为结果收集条件会产生两个结果:

(1)路径长度符合条件时收集结果并返回

(2)剪枝优化:搜索集末尾剪枝

可以通过控制单个节点内下一步访问的搜索集的末尾位置

实现方式未

回溯树的末端指针从n调整到n - (k - len(path)) + 1

题目:

77. 组合

理解起来就是把末尾的(k - len(path))个路径去掉,

以长度作为结果收集条件的题目总搜索集长度 > 路径长度 + 节点内搜索集宽度

节点内搜索集宽度太大了,路径长度就达不到要求,

所以需要把回溯树的宽度从n调整到n - (k - len(path)) + 1,

末尾的+1是本轮访问的节点

1.2 求和值大小

类似于长度,也是有两个影响:

(1)路径求和等于目标数时收集结果并返回,大于目标数直接返回

(2)剪枝优化:排序break剪枝,

将搜索集排序,求和大于目标数舍弃节点所有后续路径

题目:

216. 组合总和 III

39. 组合总和

40. 组合总和 II

实现方式为:

如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历

注意主函数种要对总搜索集排序

2.分割:分割片段的约束条件

分割类题目对分割片段有特殊的要求,因此常采用以下模板范式:

def is_valid(self, 参数):
    判断条件

def backtracking(self, 输入参数, start_idx, path, ans):
    if 终止条件
        存放结果
        return

    for i in range(start_idx, len(总搜索集)):
        if self.is_valid(参数):
            处理节点
            self.backtracking(输入参数, start_idx + 1, path, ans) // 递归
            回溯,撤销处理结果

题目:

131. 分割回文串

93. 复原 IP 地址

3.其他特殊约束条件:棋盘、安排行程等

该类题,常常需要复杂的判断条件或在主函数中对搜索集预处理(常用哈希表)来辅助判断约束条件

其中复杂的判断条件可能导致超时,

在主函数中对搜索集预处理(常用哈希表)来辅助判断比较常用

题目:(预处理方式)

安排行程:map哈希表:

332. 重新安排行程

棋盘:数组哈希表:

51. N 皇后

37. 解数独

三、去重

1.组合问题中的去重

如果搜索集存在重复元素,则需要进行同层重复剪枝操作来去重,

否则由于回溯树中同一层存在重复元素,使得多条路径通向同一个结果

导致重复的组合结果,

去重方法可以分为索引去重数值去重,但都需要排序

其中排序有两个作用:使相同数字紧贴防止异层重复访问

防止异层重复访问是去重能够在层内进行的前提,

索引去重便是利用相同数字紧贴的特性去重,有简单写法数组写法两种写法

数值去重则是在层内统计同一个数值的使用情况来去重,不需要排序的第一个功能,

更详细介绍在刷题记录 回溯算法-13:90. 子集 II-CSDN博客

题目:

40. 组合总和 II

90. 子集 II

491. 非递减子序列

其中491. 非递减子序列情况特殊,只能用数值去重,详见刷题记录 回溯算法-14:491. 非递减子序列-CSDN博客

2.排列问题中的去重

和组合问题略有不同,排列问题除了层内去重还可以倒序去重,

层内去重逻辑和组合去重类似,索引去重数值去重都可以用,同样需要排序

但索引去重的简单写法无法使用,只能用数组写法

倒序去重很少用,以上详见:

刷题记录 回溯算法-16:47. 全排列 II-CSDN博客

题目:47. 全排列 II

四、遍历与搜索(递归函数返回)

大部分题目需要找到所有结果,但有些题目找到一个结果即可返回,其代码结构会出现一些变化

1.收集所有结果

大部分题目都需要用一个数组收集所有符合条件的结果,

这也是总模板适配的情况

def backtracking(self, 参数):
    if 终止条件
        存放结果
        return

    for 选择:本层集合中元素(树中节点孩子的数量就是集合的大小):
        处理节点
        self.backtracking(路径,选择列表) // 递归
        回溯,撤销处理结果

2.找到一个结果

有些题目只需要找到一个结果即可,且往往尝试找到所有结果会导致超时,

这种情况需要用返回值在找到结果后快速返回主函数:

def backtracking(self, 参数):
    if 终止条件
        存放结果
        return True

    for 选择:本层集合中元素(树中节点孩子的数量就是集合的大小):
        处理节点
        if self.backtracking(路径,选择列表):  # 递归
            return True
        回溯,撤销处理结果
    return False

修改分为三处:

1.终止条件返回True

2.递归调用返回True

3.函数末尾返回False 

题目:

332. 重新安排行程

37. 解数独

建议的复习方法

回溯算法类型的题目有较为统一的模板和容易识别的题目类型,

但各个类型都会有格子需要注意的点,

因此建议先简单过一遍模式识别树,熟悉模板和思路

然后按题目类型顺序逐个类型过一遍算法题,强化各个类型的特定模式

当遇到不熟悉的模式识别环节,就做一下特定模式识别环节的强化练习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/959187.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【博客之星】年度总结:在云影与墨香中探寻成长的足迹

🐇明明跟你说过:个人主页 🔖行路有良友,便是天堂🔖 目录 一、年度回顾 1、创作历程 2、个人成长 3、个人生活与博客事业 二、技术总结 1、赛道选择 2、技术工具 3、实战项目 三、前景与展望 1、云原生未来…

Adobe的AI生成3D数字人框架:从自拍到生动的3D化身

一、引言 随着人工智能技术的发展,我们见证了越来越多创新工具的出现,这些工具使得图像处理和视频编辑变得更加智能与高效。Adobe作为全球领先的创意软件公司,最近推出了一项令人瞩目的新技术——一个能够将普通的二维自拍照转换成栩栩如生的三维(3D)数字人的框架。这项技…

【Nacos】负载均衡

目录 前言 一、服务下线二、权重配置三、同一个集群优先访问四、环境隔离 前言 我们的生产环境相对是比较恶劣的,我们需要对服务的流量进行更加精细的控制.Nacos支持多种负载均衡策略,包括配置权重,同机房,同地域,同环…

回首2024,展望2025

2024年,是个充满挑战与惊喜的年份。在这366个日夜里,我站在编程与博客的交汇点,穿越了无数的风景与挑战,也迎来了自我成长的丰收时刻。作为开发者的第十年,我依然步伐坚定,心中始终带着对知识的渴望与对自我…

net Core Ocelot(1)单地址,多地址

Ocelot 网关技术 》》》配置文件 》》》单地址 {"Routes": [{// 上游 》》 接受的请求//上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法"UpstreamHttpMethod": [ "Get", "Post" ],"UpstreamPathTe…

计算机图形学:实验三 光照与阴影

一、程序功能设计 设置了一个3D渲染场景,支持通过键盘和鼠标控制交互,能够动态调整光源位置、物体材质参数等,具有光照、阴影和材质效果的场景渲染。 OpenGL物体渲染和设置 创建3D物体:代码中通过 openGLObject 结构体表示一个…

22_解析XML配置文件_List列表

解析XML文件 需要先 1.【加载XML文件】 而 【加载XML】文件有两种方式 【第一种 —— 使用Unity资源系统加载文件】 TextAsset xml Resources.Load<TextAsset>(filePath); XmlDocument doc new XmlDocument(); doc.LoadXml(xml.text); 【第二种 —— 在C#文件IO…

JavaScript 数组的map和join方法、延迟函数、location对象、本地存储、正则表达式、箭头函数

数组处理方法 map方法 map方法的作用是遍历数组所有元素&#xff0c;然后执行处理操作&#xff0c;最后返回一个新的数组 语法格式&#xff1a;新数组 原来数组.map(function(ele,index){ ele是数组元素&#xff0c;index是下标 执行完操作之后使用return 返回一个…

物联网网关Web服务器--CGI开发实例BMI计算

本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境&#xff1a;飞腾派开发板&#xff08;国产E2000处理器&#xff09; 软件环境&#xff1a;飞腾派OS&#xff08;Phytium Pi OS&#xff09; 硬件平台参考另一篇博客&#xff1a;国产化ARM平台-飞腾派开发板…

【论文+源码】diffuseq使用扩散模型和diffuseq-v2的序列文本生成序列,并且桥接离散和连续的文本空间,用于加速SEQ2SEQ扩散模型。

这篇论文介绍了一种名为DIFFUSEQ的新型扩散模型&#xff0c;专门针对序列到序列&#xff08;SEQ2SEQ&#xff09;文本生成任务进行设计。尽管扩散模型在视觉和音频等连续信号领域取得了成功&#xff0c;但在自然语言处理特别是条件生成方面的适应仍然未被广泛探索。通过广泛的评…

2024年度总结:技术探索与个人成长的交织

文章目录 前言年度创作回顾&#xff1a;技术深耕与分享数据库技术&#xff1a;MySQL 与 MyBatisJava 及相关技术栈计算机网络&#xff1a;构建网络知识体系思维方式的转变&#xff1a;构建技术知识体系的桥梁 项目实践&#xff1a;人工智能与智慧医疗的碰撞生活与博客的融合与平…

如何使用LDAP-Monitoring-Watchdog实时监控 LDAP 目录中记录修改

关于LDAP-Monitoring-Watchdog LDAP-Monitoring-Watchdog是一种用于实时监控 LDAP 目录中记录更改的工具&#xff0c;该工具能够与Linux兼容&#xff0c;用于检测目录变化&#xff0c;为管理员和安全研究人员提供对添加、修改和删除的可见性。 该工具提供了一种机制来跟踪和可…

Cloudflare通过代理服务器绕过 CORS 限制:原理、实现场景解析

第一部分&#xff1a;问题背景 1.1 错误现象复现 // 浏览器控制台报错示例 Access to fetch at https://chat.qwenlm.ai/api/v1/files/ from origin https://ocr.doublefenzhuan.me has been blocked by CORS policy: Response to preflight request doesnt pass access con…

深入理解动态规划(dp)--(提前要对dfs有了解)

前言&#xff1a;对于动态规划&#xff1a;该算法思维是在dfs基础上演化发展来的&#xff0c;所以我不想讲的是看到一个题怎样直接用动态规划来解决&#xff0c;而是说先用dfs搜索&#xff0c;一步步优化&#xff0c;这个过程叫做动态规划。&#xff08;该文章教你怎样一步步的…

速通Docker === Docker Compose

目录 Docker Compose 简介 Docker Compose 常用命令 使用 Docker Compose 启动 WordPress 普通启动方式&#xff08;使用 Docker 命令&#xff09; 使用 Docker Compose 启动 Docker Compose 的特性 Docker Compose 简介 Docker Compose 是一个用于定义和运行多容器 Dock…

知识体系_统计学_03_描述性统计_概括性度量

对数据的概括性度量可从三方面进行测量和描述&#xff1a;集中趋势、离中趋势和分布形态。 集中趋势&#xff0c;反映的是各数据向其中心值靠拢或聚集的程度&#xff1b;离中趋势&#xff0c;反映的是数据的离散程度&#xff0c;远离中心值的趋势&#xff1b;分布形态反映的是…

HackTheBox靶机:Sightless;NodeJS模板注入漏洞,盲XSS跨站脚本攻击漏洞实战

HackTheBox靶机&#xff1a;Sightless 渗透过程1. 信息收集常规探测深入分析 2. 漏洞利用&#xff08;CVE-2022-0944&#xff09;3. 从Docker中提权4. 信息收集&#xff08;michael用户&#xff09;5. 漏洞利用 Froxlor6. 解密Keepass文件 漏洞分析SQLPad CVE-2022-0944 靶机介…

Qt Creator 15.0.0如何更换主题和字体

1.打开Qt Creator 15.0.0 (Community)&#xff0c; 2.点击编辑栏3.点击Preferences... 4.修改主题&#xff0c;点击环境&#xff0c;修改Theme:栏 5.修改字体大小&#xff0c;点击文本编辑器&#xff0c;修改字号栏。&#xff0c;修改Theme:栏

深度强化学习:PPO

深度强化学习算法&#xff1a;PPO 1. Importance Sampling 先说一下什么是采样&#xff1a;对于一个随机变量&#xff0c;我们通常用概率密度函数来描述该变量的概率分布特性。具体来说&#xff0c;给定随机变量的一个取值&#xff0c;可以根据概率密度函数来计算该值对应的概…

亚博microros小车-原生ubuntu支持系列:11手指控制与手势识别

识别框架还是沿用之前的了MediaPipe Hand。 背景知识不摘重复&#xff0c;参见之前的&#xff1a;亚博microros小车-原生ubuntu支持系列&#xff1a;10-画笔-CSDN博客 手指控制 src/yahboom_esp32_mediapipe/yahboom_esp32_mediapipe/目录下新建文件10_HandCtrl.py&#xff…