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

news2024/11/19 6:32:08

最近在刷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.coloradmin.cn/o/2200173.html

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

相关文章

【优选算法】--- 位运算

位运算 一、常见的位运算总结&#xff08;重点&#xff01;&#xff09;1、关于位运算的符号2、&#xff08;判断&#xff09;给一个数字n&#xff0c;确定它的二进制表示中的第X位&#xff0c;是1还是0&#xff1f;3、&#xff08;修改&#xff09;如何把一个二进制的数字的第…

算法:双指针系列(一)

双指针系列 一、移动零&#xff08;一&#xff09;题目分析&#xff08;二&#xff09;代码展示二、复写零&#xff08;一&#xff09;题目分析&#xff08;二&#xff09;代码展示三、快乐数&#xff08;一&#xff09;题目分析&#xff08;二&#xff09;代码展示&#xff08…

OceanBase 4.x 部署实践:如何从单机扩展至分布式部署

OceanBase 4.x 版本支持2种部署模式&#xff1a;单机部署与分布式部署&#xff0c;同时支持从单机平滑扩展至分布式架构。这样&#xff0c;可以有效解决小型业务向大型业务转型时面临的扩展难题&#xff0c;降低了机器资源的成本。 以下将详述如何通过命令行&#xff0c;实现集…

Matlab数据预处理——最小二乘法消除多项式趋势项

关注公众号“电击小子程高兴的MATLAB小屋”获取专属优惠 概要&#xff1a; 最小二乘法是一种常用的统计方法&#xff0c;用于通过拟合数据来消除多项式趋势项。以下是关于如何使用最小二乘法消除多项式趋势项的步骤和概念&#xff1a; 概念&#xff1a; 多项式趋势项&#…

动态规划一>解码方法

1.题目&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; 2.解析&#xff1a; 版本一&#xff1a;图解&#xff1a; 注意&#xff1a; 前导0不能解码&#xff1a;06, 或者两个数字字符&#xff1a;其中一个解码失败&#xff0c;整个也解码失败 /**1.创建dp表2.初始化3.填…

GIS小技巧——一文教会你安装BlenderGIS插件

Blender是一款不错的三维渲染软件&#xff0c;用它来做三维地形图&#xff0c;能够更好地把地形纹理显现出来。不过&#xff0c;原始的Blender是没有地图底图的&#xff0c;要结合三维影像制作三维地形图&#xff0c;需要结合其他的软件&#xff0c;比如ArcGIS Pro&#xff0c;…

基于RSSI原理的蓝牙定位程序(matlab代码,3维空间、基站数量>3即可,可自适应)

目录 商品描述 商品描述 这款基于接收信号强度指示&#xff08;RSSI&#xff09;原理的蓝牙定位程序&#xff0c;专为需要高效、可靠定位解决方案的开发者和研究人员设计。无论是在室内环境还是复杂的三维空间&#xff0c;该程序都能通过N个蓝牙锚点&#xff0c;实现对未知点的…

重学SpringBoot3-集成Redis(十)之实时统计和分析

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;十&#xff09;之实时统计和分析 1. 实时统计和分析的常见场景2. 使用 Redis 数据结构进行实时统计3. 使用Redis String实现计数器…

linux线程 | 一篇文章带你理解线程的概念

前言:本篇讲述linux里面线程的相关概念。 线程在我们的教材中的定义通常是这样的——线程是进程的一个执行分支。 线程的执行粒度&#xff0c; 要比进程要细。 我们在读完这句话后其实并不能很好的理解什么是线程。 所以&#xff0c; 本节内容博主将会带友友们理解什么是线程&a…

vscode软件中可以安装的一些其他插件

一. 简介 前面了解了 在 做 C开发时 vscode软件需要安装的一些常用插件。文章如下&#xff1a; vscode软件在 C发中常用插件-CSDN博客 本文继续了解一些其他好用的插件。 二. vscode软件中可以安装的一些其他插件 1. 字体插件 FIRA CODE FIRA CODE 致力于提升代码的连贯…

Chromium 中chrome.history扩展接口c++实现

一、前端 chrome.history定义 使用 chrome.history API 与浏览器的已访问网页的记录进行交互。您可以在浏览器的历史记录中添加、移除和查询网址。如需使用您自己的版本替换历史记录页面&#xff0c;请参阅覆盖网页。 更多参考&#xff1a;chrome.history | API | Chrome…

LSTM 长短期记忆网络:解锁时间序列数据的深层秘密

在这个数据驱动的时代&#xff0c;理解和预测时间序列数据成为了许多领域的关键。从股票价格预测到天气模式分析&#xff0c;从自然语言处理到健康监测&#xff0c;时间序列数据无处不在&#xff0c;并且蕴含着丰富的信息。然而&#xff0c;传统的神经网络在处理这类数据时往往…

Openstack 安装教程

1.首先更新系统 sudo apt update sudo apt upgrade -y2.安装必要软件包 sudo apt install -y software-properties-common3.添加openstack官方仓库 sudo add-apt-repository cloud-archive:train sudo apt update4.安装openstack核心组件 sudo apt install -y python3-opens…

技术分享 —— JMeter接口与性能测试实战!

前言 在软件开发和运维过程中&#xff0c;接口性能测试是一项至关重要的工作。JMeter作为一款开源的Java应用&#xff0c;被广泛用于进行各种性能测试&#xff0c;包括接口性能测试。本文将详细介绍如何使用JMeter进行接口性能测试的过程和步骤。 JMeter是Apache组织开发的基…

Redis-02 持久化

redis持久化即将数据从内存写入磁盘&#xff0c;Redis提供了两种持久化的方式&#xff1a;RDB和AOF。 1.RDB RDB持久化&#xff1a;Redis可以将内存中的数据定期快照保存到磁盘上的一个二进制文件中。RDB持久化是一种比较紧凑的文件格式&#xff0c;适用于备份和灾难恢复。通过…

陈零九全新单曲《也曾想走进你的心底》 揭露爱而不得的情感遗憾

图片提供&#xff1a;种子音乐 “创作男神”陈零九于10月9日推出充满深情的全新创作单曲《也曾想走进你的心底》&#xff0c;这首歌再次延续他招牌的“九式情歌”风格&#xff0c;展现其创作魅力。歌曲以一段“爱而不得”的感情故事为主线&#xff0c;深入探讨人们在爱情中的复…

java家政预约上门系统源码,家政服务平台源码,基于SpringBoot框架,数据库使用MySQL,界面渲染采用Thymeleaf技术开发

自主知识产权的家政预约上门系统源码&#xff0c;java版本&#xff0c;支持二次开发&#xff0c;适合商用上项目。 在这个快节奏的现代生活中&#xff0c;越来越多的家庭开始寻求高效、便捷的家政服务解决方案。传统的家政服务模式已经很难满足人们日益增长的个性化与即时性需求…

GAMES202作业3

EvalDiffuse 对于一个diffuse的着色点&#xff0c;它的BRDF为&#xff1a; /** Evaluate diffuse bsdf value.** wi, wo are all in world space.* uv is in screen space, [0, 1] x [0, 1].**/ vec3 EvalDiffuse(vec3 wi, vec3 wo, vec2 uv) {vec3 albedo GetGBufferDiffus…

【Linux】基本认知全套入门

目录 Linux简介 Linux发行版本 发行版选择建议 Centos-社区企业操作系统 Centos版本选择 Linux系统目录 Linux常用命令 SSH客户端 Linux文件操作命令 vim重要快捷键 应用下载与安装 netstat&#xff0c;ps与kill命令使用 Linux应用服务化 Linux用户与权限 Linu…

接口自动化测试实战

测试前准备&#xff1a; 1、项目的介绍 是一个什么项目、项目技术、项目要测的接口和业务流程、业务路径测试用例&#xff08;通过业务流程来梳理业务路径&#xff09; 2、链接和登录密码&#xff1a; 客达天下http://huike-crm.itheima.net/#/clue 客达天下账号admin&…