二叉树中的最大路径和给定一棵非空二叉树路径由相邻节点组成每个节点最多经过一次。路径不必经过根节点也不必从叶子节点开始或结束。例如在下面的二叉树中最大路径是15 → 20 → 7最大路径和是15 20 7 42。-10 / \ 9 20 / \ 15 7一、解题思路当前节点必须先得到左右子树的计算结果所以采用“左子树、右子树、当前节点”的后序遍历。递归函数maxGain(root)的返回值不是整棵树的最大路径和而是“从当前节点出发只向一侧延伸时能够返回给父节点的最大路径和”。对于当前节点左、右子树的贡献分别为leftGain和rightGain。如果某个贡献是负数连接这棵子树只会使路径和变小因此通过Math.max(0, 子树贡献)将它舍弃。一条路径如果在当前节点处结束可以同时连接左右两侧所以用root.val leftGain rightGain更新全局变量maxSum。但当前节点向父节点返回时路径还要继续向上连接不能同时保留左右两侧否则路径会产生分叉。因此只能返回root.val Math.max(leftGain, rightGain)。以节点20为例左右子树分别返回15和7。经过节点20的完整路径和是15 20 7 42所以用42更新maxSum而节点20返回给父节点时只能选择较大的一侧因此返回20 max(15, 7) 35。两种结果的职责不同root.val leftGain rightGain 用于更新整棵树的最大路径和 root.val max(leftGain, rightGain) 用于返回给父节点继续计算全局变量maxSum必须初始化为Integer.MIN_VALUE。如果整棵树都是负数最大路径和应当是其中最大的节点值而不是0。二、完整代码publicclassBinaryTreeMaximumPathSum{staticclassTreeNode{intval;TreeNodeleft;TreeNoderight;TreeNode(intval){this.valval;}}/** * 遍历过程中发现的最大完整路径和。 */privateintmaxSum;publicintmaxPathSum(TreeNoderoot){maxSumInteger.MIN_VALUE;// 启动后序遍历递归过程中会更新 maxSum。maxGain(root);returnmaxSum;}/** * 返回从当前节点出发只向一侧延伸时 * 能够提供给父节点的最大路径和。 */privateintmaxGain(TreeNoderoot){if(rootnull){return0;}intleftGainMath.max(0,maxGain(root.left));intrightGainMath.max(0,maxGain(root.right));// 完整路径可以同时连接左右两侧。intcurrentPathSumroot.valleftGainrightGain;maxSumMath.max(maxSum,currentPathSum);// 返回父节点时只能选择一侧。returnroot.valMath.max(leftGain,rightGain);}publicstaticvoidmain(String[]args){/* * -10 * / \ * 9 20 * / \ * 15 7 */TreeNoderootnewTreeNode(-10);root.leftnewTreeNode(9);root.rightnewTreeNode(20);root.right.leftnewTreeNode(15);root.right.rightnewTreeNode(7);BinaryTreeMaximumPathSumsolutionnewBinaryTreeMaximumPathSum();intresultsolution.maxPathSum(root);System.out.println(最大路径和result);}}程序输出最大路径和42每个节点只计算一次所以时间复杂度为O(n)递归调用栈的最大深度等于树高所以空间复杂度为O(h)。三、压栈、出栈与返回父节点程序首先进入maxPathSum(-10)将maxSum初始化为最小整数然后调用maxGain(-10)。此时maxPathSum暂停等待整棵树递归结束。栈顶 ┌──────────────────────────┐ │ maxGain(-10) │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底maxGain(-10)先计算左子树因此调用maxGain(9)。节点-10的栈帧不会消失而是留在栈中等待左子树返回。栈顶 ┌──────────────────────────┐ │ maxGain(9) │ ├──────────────────────────┤ │ maxGain(-10)等待左结果 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底节点9的左右子树都是空节点所以leftGain 0、rightGain 0。经过节点9的完整路径和为9 0 0 9因此将maxSum更新为9随后节点9向父节点-10返回9 max(0, 0) 9并从调用栈中弹出。栈顶 ┌──────────────────────────┐ │ maxGain(-10) │ │ leftGain 9 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底 maxSum 9得到左子树结果后maxGain(-10)调用maxGain(20)计算右子树。节点20又先调用maxGain(15)因此栈中依次保存根节点和正在等待结果的父节点。栈顶 ┌──────────────────────────┐ │ maxGain(15) │ ├──────────────────────────┤ │ maxGain(20)等待左结果 │ ├──────────────────────────┤ │ maxGain(-10)等待右结果 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底节点15没有孩子所以经过它的完整路径和是15maxSum从9更新为15。节点15向父节点20返回15然后出栈。回到节点20后leftGain 15。接着调用maxGain(7)计算右子树栈顶 ┌──────────────────────────┐ │ maxGain(7) │ ├──────────────────────────┤ │ maxGain(20)等待右结果 │ ├──────────────────────────┤ │ maxGain(-10)等待右结果 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底节点7没有孩子所以向父节点20返回7然后出栈。此时节点20已经得到leftGain 15和rightGain 7。栈顶 ┌──────────────────────────┐ │ maxGain(20) │ │ leftGain 15 │ │ rightGain 7 │ ├──────────────────────────┤ │ maxGain(-10)等待右结果 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底经过节点20的完整路径和是15 20 7 42所以maxSum更新为42。节点20向父节点-10返回时只能选择一侧因此返回20 max(15, 7) 35然后出栈。回到根节点-10后左右子树的返回值分别是9和35。栈顶 ┌──────────────────────────┐ │ maxGain(-10) │ │ leftGain 9 │ │ rightGain 35 │ ├──────────────────────────┤ │ maxPathSum等待递归结束 │ └──────────────────────────┘ 栈底 maxSum 42经过根节点的完整路径和是9 (-10) 35 34小于当前的42所以maxSum不变。根节点还会计算单边返回值-10 max(9, 35) 25但根节点没有父节点所以这个返回值没有被使用。maxGain(-10)出栈后程序回到maxPathSum。栈顶 ┌──────────────────────────┐ │ maxPathSum │ │ maxSum 42 │ └──────────────────────────┘ 栈底最后maxPathSum返回maxSum结果为42。整个过程只有一条数据链子节点返回单边贡献 ↓ 父节点组合左右贡献 ↓ 更新全局最大路径和 ↓ 父节点再返回自己的单边贡献maxGain的返回值供父节点继续计算maxSum记录遍历过程中出现的最大完整路径maxPathSum在递归结束后返回最终结果。
企业数字化 ERP 产品动态
相关推荐
深入理解二叉树遍历:从递归代码到调用栈 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 2:18:22
Mac 菜单栏电池状态监控:SketchyBar 电量插件实用上手 Mac 菜单栏电池状态监控:SketchyBar 电量插件实用上手 【免费下载链接】SketchyBar A highly customizable macOS status bar replacement 项目地址: https://gitcode.com/gh_mirrors/sk/SketchyBar
打开 MacBook 的盖子,视线扫到右上角的菜单栏&… · 2026/11/3 2:17:22
仓库越大越乱?一家郑州五金批发商的“仓库翻身仗“ 一、凌晨一点,老板还在仓库里找一颗螺丝郑州某五金行业的老板,曾经有个外号叫"仓库里的夜猫子"。仓库两千平,货架一排接一排,五金工具、机电配件、紧固件加起来三万多个品项。客户一个电话要某个型号的轴承,… · 2026/11/3 2:47:27
内网安全第一道闸:为什么你的网络总被 “陌生人“ 混进来? 引言
做过网络 / 安全的都知道,内网失守往往不是防火墙没配好,而是门没看住—— 员工把个人手机、无线路由、不知名摄像头偷偷插进交换机,一台带病毒的工作站随意接入,双网卡电脑绕过隔离直连互联网…… 等你发现时,数… · 2026/11/3 2:47:27
FA_CNN卷积神经网络十九---模型选择、欠拟合与过拟合 FA:Formular and Algorithm,CNN:Convoluation Neural Network
1. 写在前面:为什么用多项式讲模型选择
在深度学习中,"模型选择"听起来抽象,但它的本质问题非常朴素:给定一份数据&… · 2026/11/3 2:47:27
经验丰富的汽车安装车载手机互联苹果Carplay和华为Hicar哪家专业 最近好几个朋友都问我,车子上想装个CarPlay或者HiCar,到底去哪里弄靠谱。说真的,我太懂这种纠结了。我自己那台车,当初就是冲着车机互联去的,结果在路边店装完,先是连不上,后来好不容易连上了&a… · 2026/11/3 2:47:27
GitLab 私有化部署太吃内存:只留仓库和合并请求 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 2:46:27
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18