每天一道算法练习题--Day19 第一章 --算法专题 --- ----------回溯

news2024/11/18 11:32:37

回溯

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

通俗上讲,回溯是一种走不通就回头的算法。

回溯的本质是穷举所有可能,尽管有时候可以通过剪枝去除一些根本不可能是答案的分支, 但是从本质上讲,仍然是一种暴力枚举算法。

回溯法可以抽象为树形结构,并且是是一颗高度有限的树(N 叉树)。回溯法解决的都是在集合中查找子集,集合的大小就是树的叉树,递归的深度,构成树的高度。

以求数组 [1,2,3] 的子集为例:
在这里插入图片描述

for 循环用来枚举分割点,其实区间 dp 分割区间就是类似的做法

以上图来说, 我们会在每一个节点进行加入到结果集这一次操作。

在这里插入图片描述

对于上面的灰色节点, 加入结果集就是 [1]。

在这里插入图片描述

这个加入结果集就是 [1,2]。

在这里插入图片描述

而对于全排列问题则会在叶子节点加入到结果集,不过这都是细节问题。掌握了思想之后, 大家再去学习细节就会事半功倍。

下面我们来看下具体代码怎么写。

算法流程

伪代码:

const visited = {}
function dfs(i) {
	if (满足特定条件){
		// 返回结果 or 退出搜索空间
	}

	visited[i] = true // 将当前状态标为已搜索
	dosomething(i) // 对i做一些操作
	for (根据i能到达的下个状态j) {
		if (!visited[j]) { // 如果状态j没有被搜索过
			dfs(j)
		}
	}
	undo(i) // 恢复i
}

剪枝

回溯题目的另外一个考点是剪枝, 通过恰当地剪枝,可以有效减少时间,比如我通过剪枝操作将石子游戏 V的时间从 900 多 ms 优化到了 500 多 ms。

剪枝在每道题的技巧都是不一样的, 不过一个简单的原则就是避免根本不可能是答案的递归。

举个例子: 842. 将数组拆分成斐波那契序列

题目描述:

给定一个数字字符串 S,比如 S = "123456579",
我们可以将它分成斐波那契式的序列 [123, 456, 579]。

形式上,斐波那契式序列是一个非负整数列表 F,且满足:

0 <= F[i] <= 2^31 - 1,(也就是说,每个整数都符合 32 位有符号整数类型);
F.length >= 3;
对于所有的0 <= i < F.length - 2,都有 F[i] + F[i+1] = F[i+2] 成立。
另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 0 本身。

返回从 S 拆分出来的任意一组斐波那契式的序列块,如果不能拆分则返回 []。



示例 1:

输入:"123456579"
输出:[123,456,579]
示例 2:

输入: "11235813"
输出: [1,1,2,3,5,8,13]
示例 3:

输入: "112358130"
输出: []
解释: 这项任务无法完成。
示例 4:

输入:"0123"
输出:[]
解释:每个块的数字不能以零开头,因此 "01""2""3" 不是有效答案。
示例 5:

输入: "1101111"
输出: [110, 1, 111]
解释: 输出 [11,0,11,11] 也同样被接受。


提示:

1 <= S.length <= 200
字符串 S 中只含有数字。

还是直接套回溯模板即可解决。但是如果不进行合适地剪枝,很容易超时,这里我进行了四个剪枝操作,具体看代码。

class Solution:
    def splitIntoFibonacci(self, S: str) -> List[int]:
        def backtrack(start, path):
            # 剪枝1
            if len(path) > 2 and path[-1] != path[-2] + path[-3]:
                return []
            if start >= len(S):
                if len(path) > 2:
                    return path
                return []

            cur = 0
            ans = []
            # 枚举分割点
            for i in range(start, len(S)):
                # 剪枝2
                if i > start and S[start] == '0':
                    return []
                cur = cur * 10 + int(S[i])
                # 剪枝3
                if cur > 2**31 - 1:
                    return []
                path.append(cur)
                ans = backtrack(i + 1, path)
                # 剪枝 4
                if len(ans) > 2:
                    return ans
                path.pop()
            return ans

        return backtrack(0, [])

剪枝过程用图表示就是这样的:
在这里插入图片描述
剪枝算法回溯的一大考点,大家一定要掌握。

笛卡尔积

一些回溯的题目,我们仍然也可以采用笛卡尔积的方式,将结果保存在返回值而不是路径中,这样就避免了回溯状态,并且由于结果在返回值中,因此可以使用记忆化递归, 进而优化为动态规划形式。

参考题目:

这类问题不同于子集和全排列,其组合是有规律的,我们可以使用笛卡尔积公式,将两个或更多子集联合起来。

经典题目

在这里插入图片描述

总结

回溯的本质就是暴力枚举所有可能。要注意的是,由于回溯通常结果集都记录在回溯树的路径上,因此如果不进行撤销操作, 则可能在回溯后状态不正确导致结果有差异, 因此需要在递归到底部往上冒泡的时候进行撤销状态。

如果你每次递归的过程都拷贝了一份数据,那么就不需要撤销状态,相对地空间复杂度会有所增加。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建线索二叉树

创建线索二叉树 一、创建线索二叉树一、案例1、前序线索二叉树2、中序线索二叉树3、后序线索二叉树 一、创建线索二叉树 现将某结点的空指针域指向该结点的前驱后继&#xff0c;定义规则如下&#xff1a; 若结点的左子树为空&#xff0c;则该结点的左孩子指针指向其前驱结点。…

【开源项目】Build your own X 构建自己的项目

【开源项目】Build your own X 构建自己的项目 简介 Build your own X 是一个精心收集了大量资源的项目指南&#xff0c;可以通过从头开始重新创建我们最喜爱的技术来掌握编程。 项目地址&#xff1a; https://github.com/codecrafters-io/build-your-own-x这些项目里的资源…

剑指 Offer II 052——展平二叉搜索树

文章目录 题目详情示例1示例二 方法一&#xff1a;中序遍历之后生成新的树Java完整代码实现 方法二&#xff1a;在中序遍历的过程中改变节点指向Java完整代码实现 题目详情 剑指 Offer II 052——展平二叉搜索树 给你一棵二叉搜索树&#xff0c;请 按中序遍历 将其重新排列为一…

Matlab2012a的图像处理工具箱的imshow函数

在处理图片文件时&#xff0c;除了使用matlab自带的image函数&#xff0c;还可以考虑用matlab的图像处理工具箱。这个工具箱提供了imshow和imtool两个函数&#xff0c;可实现图片的显示。 这两个函数都支持Handle Graphics体系结构&#xff0c;它们可创建图像对象&#xff0c;…

【AWS入门】AWS CICD

目录 一 .TASK二. 环境准备IAM创建存储库ec2-repoec2-wp 三. Code Deploy创建应用程序创建部署组创建管道部署后的ec2-wp 一 .TASK 创建2台EC2实例&#xff0c;一台名为「ec2-repo」&#xff0c;用作开发环境&#xff0c;将编写好的代码提交至repository(需安装git)&#xff0…

二十六、ISIS技术总结

文章目录 ISIS 概述一、路由协议总结1、路由优先级2、分类 二、ISIS 协议特点1、特点2、ISIS 路由器的种类 三、ISIS 配置1、基础配置2、network-entity含义3、router id 和系统id转换规则 四、ISIS 开销计算1、Narrow 模式2、Wide 模式 五、 ISIS 和 OSPF 的区别 ISIS 概述 I…

TortoiseGit提示No supported authentication methods available异常

TortoiseGit他属于git的客户端&#xff0c;可有可无&#xff0c;说白了就是将git命令给我们整理成了可直接操作的按钮。 本地代码是使用了SSH的方式去拉取的代码&#xff0c;但是通过TortoiseGit pull代码的时候发生了如下异常&#xff0c;而GitBash却可以正常使用。 TortoiseG…

机器学习技术-激活函数

激活函数 作用 f(*)称为激活函数或激励函数&#xff08;Activation Function&#xff09;&#xff0c;激活函数的主要作用是完成数据的非线性变换&#xff0c;解决线性模型的表达、分类能力不足的问题;如果网络中都是线性变换&#xff0c;则多层网络可以通过矩阵变换&#xf…

C6678学习-EDMA

文章目录 1、简介1. EDMA3概述2、EDMA3的组成3、EDMA3的工作流程4、EDMA3通道控制器&#xff08;EDMA3CC&#xff09;5、触发方式 2、EDMA3的传输1、传输数据块的定义2、传输类型3、参数PaRAM4、通道5、OPT参数 3、补充1、EDMA3通道控制器区域 1、简介 1. EDMA3概述 基于C66x…

车载滤波器组件焊锡开裂失效分析

案例背景 车载滤波器组件在可靠性试验后&#xff0c;主板上的插件引脚焊点发生开裂异常。 分析过程 焊点外观 说明&#xff1a;插件器件引脚呈现出明显的焊点开裂状态。 X-RAY检测 针对异常焊点的X-RAY检测&#xff1a; 说明&#xff1a;通孔&#xff08;支撑孔&#xff09;的透…

如何用ChatGPT做项目管理?

ChatGPT可以通过创建和维护跨团队项目协作计划&#xff0c;让员工更容易理解他们的角色和职责。这个协作计划里面会包括每个团队或个人要执行的具体任务&#xff0c;每个任务最后期限和任何事情之间的依赖关系。 该场景对应的关键词库&#xff1a;&#xff08;24个&#xff09…

springboot框架开发医院云HIS 住院医生站、住院护士站功能实现

住院医生站主模块&#xff1a;包括医嘱管理、病案首页、分配入科、住院清单、我的质控等子模块 &#xff08;1&#xff09;医嘱管理功能简介 ①住院患者开立医嘱、支持医嘱复制、停止、作废等操作&#xff1b; ②医嘱类型含药品、项目、材料、嘱托&#xff1b; ③支持住院各…

(2022 IV) RCBEV

这篇是清华大学发表在IV&#xff08;IEEE Transactions on Intelligent Vehicles&#xff09;上的文章: Bridging the view disparity between radar and camera features for multi-modal fusion 3d object detection 文章信息讲得比较细致&#xff0c;非常值得一看&#xff…

【人工智能】— 不确定性、先验概率/后验概率、概率密度、贝叶斯法则、朴素贝叶斯 、最大似然估计

【人工智能】— 不确定性 不确定性不确定性与理性决策基本概率符号先验概率(无条件概率)/后验概率(条件概率)随机变量概率密度联合概率分布公理完全联合分布概率演算独立性 贝叶斯法则例1例2 使用贝叶斯规则&#xff1a;合并证据朴素贝叶斯最大似然估计小结 不确定性 不确定性与…

osg::Drawable类通过setDrawCallback函数设置回调函数的说明

osg::Drawable类可以通过该类的setDrawCallback函数设置回调函数类对象。被设置的回调类对象必须从osg::Drawable::DrawCallback类派生&#xff0c;并重写drawImplementation函数&#xff0c;以实现自己特定的需求。这个回调函数每次在帧事件中都会被调用(如&#xff1a;在帧的…

SpringBoot定义优雅全局统一Restful API 响应框架二

这里解决之前留下来的问题&#xff0c;当程序没有正常返回时候 就是程序由于运行时异常导致的结果&#xff0c;有些异常我们可&#xff0c;能无法提前预知&#xff0c;不能正常走到我们return的R对象返回。这个时候该如何处理 在SpringBoot中&#xff0c;可以使用ControllerA…

AI 作画火了,如何用 Serverless 函数计算部署 Stable Diffusion?

作者&#xff1a;寒斜 立即体验基于函数计算部署 Stable Diffusion&#xff1a; https://developer.aliyun.com/topic/aigc AIGC 领域目前大火&#xff0c; 除了 Chatgpt&#xff0c;在文生图领域 Stable Diffusion 大放异彩&#xff0c;深刻的地影响着绘画、视频制作等相关…

古剑飞仙手游Linux系统服务器架设教程

安装宝塔直接运行命令即可。 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 搭建环境&#xff1a; centos 7以上系统服务器 宝塔面板安装应用如下&#xff1a; Nginx1.14 mysql5.7 php5.6 1…

HNU-操作系统OS-实验Lab1

OS_Lab1_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf &#xff08;学号 202108010XXX&#xff09; 为了实现 lab1 的目标&#xff0c;lab1 提供了 6 个基本练习和 1 个扩展练习&#xff0c;要求完成实验报告。 对实验报告的要求&#xff1a; 基于 mark…

【CSS笔记】CSS动画效果(2d、3d)之渐变色、过渡、变换、平移、缩放、旋转、倾斜、关键帧动画

这篇文章&#xff0c;主要介绍CSS动画效果&#xff08;2d、3d&#xff09;之渐变色、过渡、变换、平移、缩放、旋转、倾斜、关键帧动画。 目录 一、2d动画 1.1、渐变色 &#xff08;1&#xff09;线性渐变色 &#xff08;2&#xff09;径向渐变色 &#xff08;3&#xff0…