一入递归深似海,算法之美无止境

最近在刷leetcode hot100,在写二叉树中最大路径和的时候,看到了一个佬对递归的理解,深受启发,感觉自己对于递归的题又行了!!!   

这里给大家分享一下(建立大家先去尝试一下这道题再来看

124. 二叉树中的最大路径和

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

  • 树中节点数目范围是 [1, 3 * 104]
  • -1000 <= Node.val <= 1000

ps:这道题感觉达不到困难的级别

但佬的解题思路就是清晰,让人豁然开朗,顿悟的不仅是这道题,而是递归

这道题说难也不难,但说容易也真不是那么容易能想到的(写得比较多,但都是心得,耐心看完就更上一层楼了)。 首先就是递归的方式,很多人都对递归一头雾水,一看就会,一写就废。不用担心,这是正常现象。 下面,我们详细解释一下这道题,顺便疏通一下递归的基本思路。

我们不要先去考虑整个递归的代码怎么去写,而是要明确一个递归的主体,就是这个递归的主体要怎么构造,然后再去想边界条件,返回值等等。

1、那么,首先我们可以假设走到了某个节点,现在要面临的问题是路径的最大值问题,显然对于这种问题,每遍历到一个节点,我们都要求出包含该节点在内的此时的最大路径,并且在之后的遍历中更新这个最大值。对于该节点来说,它的最大路径currpath就等于左右子树的最大路径加上本身的值,也就是currpath = left+right+node,val,但是有一个前提,我们要求的是最大路径,所以若是left或者right小于等于0了,那么我们就没有必要把这些值加上了,因为加上一个负数,会使得最大路径变小。这里的最大路径中的最其实就是一个限定条件,也就是我们常说的贪心算法,只取最大,最好,其余的直接丢弃。

2、好了,1中的主体我们已经明确了,但是还存在一个问题,那就是left和right具体应该怎么求,也就是left和right的递归形式。显然我们要把node.left和node.right再次传输到递归函数中,重复上述的操作。但如果到达了叶子节点,是不是需要往上一层返回了呢?那么返回值又是多少呢? 我们要明确left和right的基本含义,它们表示的是最大贡献,那么一个节点的最大贡献就等于node.val+max(left,right),这个节点本身选上,然后从它的左右子树中选择最大的那个加上。 对于叶子节点也是这样,但是叶子节点的左右子树都为空,所以加上0,哎,注意看,此时是不是边界条件也出来了,当节点为空时,返回0 。 好了,至此循环的主体,返回值,边界条件都定义好了,那么整个递归的代码是不是就水到渠成了。这样一看递归也没什么了不起的!!!

ps:除了向下思考,其实也可以向上思考,比如还是遍历到了某个节点,那么这个节点向上一层走,是不是要有一个返回值呢,那么返回值是什么呢?是不是和自己原来需要的right(or left)相同,只不过现在轮到自己了,自己原来需要最大贡献,那么此时返回时就返回最大贡献,自己的最大贡献不就是node.val+max(left,right)。就像是老板一层一层的压榨员工一样。

看完这些我结合我的AI做了一个总结:  嗯,也是对这道题的一个交代吧

在递归类的题目中,可能很多人都和我一样会感到困惑,尤其是写递归的过程中常常遇到“会看不会写”的窘境。递归的本质看似简单,但在实际应用中却往往让人抓不住重点。然而,解答这类题目的关键在于理清递归的基本框架与思维路径,而一旦掌握了这个过程,递归将不再神秘。

递归的困境:一看就会,一写就废

在初学递归时,我想大家都会有一种“知道大概,但无从下手”的感觉。这是因为递归不同于其他常规的解题思路,它往往需要我们站在一个较高的抽象层次去思考问题的整体,而不是仅仅关注细节。尤其是递归中“自我调用”的特性,让人很容易在一开始时就迷失在代码的具体实现中,而忽略了逻辑上的整体构建。

解题的核心思路:先明确递归的主体

要想解决递归类问题,首先必须放下对代码细节的焦虑,回到问题本身。一个清晰的递归思路,通常可以归纳为几个关键点:递归的主体是什么?边界条件是什么?返回值是什么?这几个问题解决后,递归的代码往往也就顺理成章了。

在这道题中,我们的目标是找到一条路径的最大值。那么,这里的递归主体可以这样定义:我们在每个节点上求解“从当前节点出发,经过该节点的最大路径值”,而这一最大路径值是由当前节点的值加上它的左右子树的最大路径值之和来确定的。然而,如果左右子树的某个最大路径值为负数,显然它对我们整体路径的贡献是负的,故我们应该舍弃这些负贡献,而仅取正值部分。这其实隐含了一种贪心算法的思路:在每次递归中,我们只选择对整体有利的子路径,而放弃那些对整体无益的部分。

递归的层次结构:从上到下的自我调用

接下来,我们需要思考左右子树的最大路径值如何求解。这其实就是递归的核心——我们将问题递归分解为更小的子问题,通过不断地递归调用自身,最终在叶子节点时触发递归的终止条件。在这道题中,递归的终止条件非常自然:当我们到达叶子节点的左右子树为空时,最大路径值为0。通过这样的层层递归,最后回溯时将每个节点的最大路径值传递回去,形成了完整的递归过程。

递归的回溯:每个节点的最大贡献

在递归过程中,我们不仅向下遍历,也需要向上回溯。在每次递归回溯时,我们需要将当前节点的“最大贡献”值返回给它的上一级节点,而这个最大贡献值正是当前节点的值加上左右子树中较大的那一部分。这就像是从员工到老板逐层递交成果,老板需要下属的最大贡献,而下属则将其最佳的工作结果汇报给老板。最终,通过逐层回溯,每一层都只保留了最佳的路径贡献,从而得到了全局的最优解。

总结

递归的美妙之处在于它让问题的层次结构清晰明了。通过递归,我们不仅可以将复杂的问题逐步拆解,还能在边界条件明确的情况下逐步解决每一层次的子问题。而这种由内而外的层层递归、由下而上的逐步回溯,使得递归问题不仅在形式上简洁优美,也在逻辑上充满了挑战与成就感。写好递归的关键并不在于一开始就写出完整的代码,而在于明确递归的主体,理解问题的层次结构,顺其自然地将边界条件、返回值、递归过程一一定义出来。这样一来,递归问题自然就迎刃而解了。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是PLM系统?PLM系统对制造业起到哪些作用?三品PLM系统对汽车制造业意义

在当今竞争激烈的制造业环境中&#xff0c;企业面临着来自市场、技术、客户需求等多方面的挑战。为了应对这些挑战&#xff0c;许多制造企业纷纷引入产品生命周期管理PLM系统&#xff0c;以实现更高效、更灵活的产品全生命周期管理。PLM系统以其独特的优势&#xff0c;在优化产…

智能猫砂盆怎么选购?cewey、鸟语花香、霍曼全方位测评性能大PK

智能猫砂盆怎么选购&#xff1f;cewey、鸟语花香、霍曼全方位测评性能大PK 现在的生活节奏越来越快&#xff0c;我们经常会外出不在家&#xff0c;这时候猫咪的粑粑就不能及时清理&#xff0c;会出现猫咪嫌猫砂盆脏乱拉&#xff0c;家里空气也会充满臭味。针对这个问题&#x…

Unity3d动画插件DoTween使用指南

1、DoTween是什么&#xff1f; DoTween是一款对象动画类插件&#xff0c;它是一款针对Unity 3D编辑器的、快速高效的、安全的、面向对象的补间动画引擎&#xff0c;并且对C#语言开发做出了很多的优化。另外&#xff0c;它使得开发者无需通过Unity内置的Animator或Coroutines即可…

【Chrome浏览器插件--资源嗅探猫抓】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、资源嗅探插件---猫抓二、使用步骤总结 一、资源嗅探插件—猫抓 猫抓是一个浏览器插件&#xff0c;可以检测当前网页中的一些资源文件&#xff0c;可设置嗅探的…

用KLineChart绘制股票行情K线图

用KLineChart绘制股票行情K线图 先看效果集成过程集成到系统 先看效果 用klinechart开源代码集成到系统中&#xff0c;展示的K线图效果。 集成过程 KlineChart源码地址&#xff1a; https://github.com/klinecharts/KLineChart KlineChart提供了多种行情分析指标 集成到…

OJ在线评测系统 微服务高级 Gateway网关接口路由和聚合文档 引入knife4j库集中查看管理并且调试网关项目

Gateway微服务网关接口路由 各个服务之间已经能相互调用了 为什么需要网关 因为我们的不同服务是放在不同的端口上面的 如果前端调用服务 需要不同的端口 8101 8102 8103 8104 我们最好提供一个唯一的 给前端去调用的路径 我们学习技术的时候必须要去思考 1.为什么要用&am…

Python | Leetcode Python题解之第458题可怜的小猪

题目&#xff1a; 题解&#xff1a; class Solution:def poorPigs(self, buckets: int, minutesToDie: int, minutesToTest: int) -> int:if buckets 1:return 0combinations [[0] * (buckets 1) for _ in range(buckets 1)]combinations[0][0] 1iterations minutesT…

JavaSE——集合1:Collection接口(Iterator和增强for遍历集合)

目录 一、集合框架体系(重要) 二、集合引入 (一)集合的理解与好处 三、Collection接口 (一)Collection接口实现类的特点 (二)Collection接口常用方法 (三)Collection接口遍历元素的方式(Iterator和增强for) 1.使用Iterator(迭代器) 1.1Iterator(迭代器)介绍 1.2Itera…

[含文档+PPT+源码等]精品基于Nodejs实现的家教服务小程序的设计与实现

基于Node.js实现的家教服务小程序的设计与实现背景&#xff0c;主要源于以下几个方面&#xff1a; 一、家教市场的现状与需求 随着教育竞争的日益激烈&#xff0c;家庭对子女教育质量的重视程度不断提升&#xff0c;家教服务已成为许多家庭不可或缺的一部分。然而&#xff0c…

graphql--快速了解graphql特点

graphql--快速了解graphql特点 1.它的作用2.demo示例2.1依赖引入2.2定义schema2.3定义GrapQL端点2.4运行测试2.5一些坑 今天浏览博客时看到graphQL,之前在招聘网站上第一次接触,以为是图数据查询语言, 简单了解后,发现对graphQL的介绍主要是用作API的查询语言,不仅限于图数据查…

Meta 发布 Quest 3S 头显及 AR 眼镜原型:开启未来交互新视界

简介 在科技的浪潮中&#xff0c;Meta 始终站在创新的前沿&#xff0c;不断为我们带来令人惊叹的虚拟现实和增强现实体验。2024 年 10 月 6 日&#xff0c;让我们一同聚焦 Meta 最新发布的 Quest 3S 头显及 AR 眼镜原型&#xff08;Orion&#xff09;&#xff0c;探索这两款产品…

自由学习记录(2)

Unity打包图集相关 Draw Call 实验设置&#xff1a; 我们将创建两个场景&#xff0c;一个场景有高 Draw Call&#xff0c;另一个场景通过优化减少 Draw Call。然后对比它们的帧率&#xff08;FPS&#xff09;。 场景 1&#xff1a;高 Draw Call 场景&#xff08;无优化&…

【数据结构与算法-高阶】并查集

【数据结构与算法-高阶】并查集 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;数据结构与算法&#x1f345; &#x1f33c;文章目录&#x1f33c; 1. 并查集原理 2. 并查集实现 3. 并查集应用 1. 并查集原理 在一些应用问题中&…

了解HTTPS

目录 1.HTTP认识 2.HTTP请求 3.HTTP响应 4.URL 5.HTTP方法 面试题&#xff1a;POST 和 GET区别&#xff1f; 网上关于 GET 与 POST的差别 有待商议 关于请求报头 和 响应报头 6..Host &#xff1a; 7..USer-Agent&#xff08;简称UA&#xff09; 8.状态码 9.HTTPS 是…

读懂MySQL事务隔离

什么是事务 事务就是一组原子性的SQL查询&#xff0c;或者说一个独立的工作单元。事务内的语句&#xff0c;要么全部执行成功&#xff0c;要么全部执行失败。 关于事务银行系统的应用是解释事务必要性的一个经典例子。 假设一个银行的数据库有两张表&#xff1a;支票表&#x…

【Windows】开始菜单关键错误以及系统应用闪退问题记录

一 开始菜单关键错误 Windows长时间没有重启&#xff0c;重启之后开始菜单点不进去&#xff0c;报错“关键错误”。 查询网上有两种解决方案&#xff1a; 【1】更新系统版本&#xff1b; 【2】通过powershell执行一次性恢复所有应用的指令&#xff1b; 我这边采用第二种方法&am…

如何使用pymysql和psycopg2执行SQL语句

在Python中&#xff0c;pymysql和psycopg2是两个非常流行的库&#xff0c;用于与MySQL和PostgreSQL数据库进行交互。本文将详细介绍如何使用这两个库来执行SQL查询、插入、更新和删除操作。 1. 准备工作 首先&#xff0c;确保已经安装了pymysql和psycopg2库。如果尚未安装&a…

指针函数C++

指针函数概念 指针函数在C中是一种特殊类型的函数。从本质上讲&#xff0c;它是一个函数&#xff0c;不过其返回值是一个指针类型的数据。例如&#xff0c;像int* plusfunction(int a, int b);这样的函数声明&#xff0c;plusfunction就是一个指针函数&#xff0c;它接受两个i…

CentOS7.9 下安装 Docker

第一步&#xff1a; sudo yum install -y yum-utils \ > device-mapper-persistent-data \ > lvm2 第二步&#xff1a;安装 sudo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum -y install…

IT监控可视化:运维团队的智慧之眼

在当今这个数字化时代&#xff0c;IT系统已成为企业运营的核心支柱。随着业务的不断扩展和IT架构的日益复杂&#xff0c;运维团队面临着前所未有的挑战。如何高效、准确地监控和管理IT资源&#xff0c;确保系统的稳定性和可用性&#xff0c;成为了运维工作的重中之重。而IT监控…