声明::个人原创代码,转载请附上本文链接
题目:
题目要求
给定一个非空二叉树,计算其最大路径和。路径定义为从树中任意节点出发,沿父-子连接向下延伸的路径(不可分叉),路径和是路径中所有节点值的累加。路径至少包含一个节点,且不一定经过根节点。
关键点与变量对应
-
路径方向:向下单向(左或右子树选其一)。
-
核心变量:
-
NodeMaxValue
:当前节点为根的子树中,可能的最大路径和(包含左右子树的贡献)。 -
NodeAllowAddValue
:当前节点能为父节点提供的最大贡献值(只能选择左或右路径)。 -
flag
:标记是否已处理有效子节点贡献(用于初始化贡献值)。
-
思路分析
核心思想
通过递归计算每个节点的最大贡献值,并在递归过程中更新全局最大路径和。
递归函数目标
-
计算以当前节点为根的子树的最大路径和(可包含左右子树)。
-
计算当前节点能为父节点提供的最大贡献值(单边路径)。
贡献值规则
-
子树的贡献值若为负,则舍弃(即取0)。
-
当前节点的贡献值为
节点值 + max(左子树贡献, 右子树贡献)
。
全局最大值更新
每次递归时,计算当前节点的完整路径和(左+右+自身),并尝试更新全局最大值。
关键逻辑详解
1. 递归函数 GetOneNodeMaxValue
的流程
-
输入:当前节点
root
,全局最大值引用MaxValue
。 -
输出:当前节点能为父节点提供的最大贡献值
NodeAllowAddValue
。 -
步骤分解:
-
初始化:
-
NodeMaxValue
初始化为当前节点的值,表示仅包含自身的路径和。 -
flag
标记是否已处理子节点贡献(初始为false
)。
-
-
处理左子树:
-
递归调用左子树,获取其贡献值
NodeLeftAllowMaxValue
。 -
若左子树贡献值为正,则累加到
NodeMaxValue
(表示选择左子树路径)。 -
记录第一个有效子节点的贡献值到
NodeAllowAddValue
,并标记flag = true
。
-
-
处理右子树:
-
递归调用右子树,获取其贡献值
NodeRightAllowMaxValue
。 -
若右子树贡献值为正,则累加到
NodeMaxValue
(表示选择右子树路径)。 -
比较左右子树的贡献值,更新
NodeAllowAddValue
为较大者,并确保flag
标记正确。
-
-
更新全局最大值:
-
当前节点的完整路径和
NodeMaxValue
(左+右+自身)可能与全局最大值MaxValue
比较,取较大者。
-
-
返回贡献值:
-
返回
root->val + max(左贡献, 右贡献)
,确保路径只能向下延伸(单边选择)。
-
-
2. 全局最大值 MaxValue
的更新时机
-
更新条件:当当前节点的完整路径和(包含左右子树)大于
MaxValue
时更新。 -
意义:捕捉所有可能的路径组合,包括跨子树的路径(如示例中的根节点与左右子树组合)。
3. 贡献值的传递规则
-
贡献值计算:
NodeAllowAddValue = max(左贡献, 右贡献)
。 -
负值处理:若子树贡献值为负,则舍弃(等价于
max(0, 子树贡献)
)。 -
返回值逻辑:
return (NodeAllowAddValue > 0) ? (root->val + NodeAllowAddValue) : root->val
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
#include<climits> // 包含INT_MIN的定义
class Solution {
public:
// 递归函数:计算以当前节点为根的子树最大路径和,并更新全局最大值
// 参数:root 当前节点,MaxValue 引用传递的全局最大值
// 返回值:当前节点能为父节点提供的最大贡献值(只能选左或右路径)
int GetOneNodeMaxValue(TreeNode*& root, int& MaxValue) {
// 初始化当前节点的最大路径和为自身值(至少包含自己)
int NodeMaxValue = root->val;
// 记录可传递给父节点的最大贡献值(单边路径)
int NodeAllowAddValue;
// 标记是否存在有效子节点贡献(用于初始化贡献值)
bool flag = false;
// 处理左子树分支
if(root->left != nullptr) { // 存在左子树时递归处理
// 递归获取左子树的贡献值(若为负则自动置0)
int NodeLeftAllowMaxValue = GetOneNodeMaxValue(root->left, MaxValue);
// 若左子树贡献值为正,则累加到当前路径和(选择左子树路径)
if(NodeLeftAllowMaxValue > 0) NodeMaxValue += NodeLeftAllowMaxValue;
// 初始化贡献值(首次处理子节点时记录左子树贡献)
if(!flag) {
NodeAllowAddValue = NodeLeftAllowMaxValue; // 保存左子树贡献值
flag = true; // 标记已处理子节点
}
}
// 处理右子树分支
if(root->right != nullptr) { // 存在右子树时递归处理
// 递归获取右子树的贡献值(若为负则自动置0)
int NodeRightAllowMaxValue = GetOneNodeMaxValue(root->right, MaxValue);
// 若右子树贡献值为正,则累加到当前路径和(选择右子树路径)
if(NodeRightAllowMaxValue > 0) NodeMaxValue += NodeRightAllowMaxValue;
// 更新贡献值为左右子树中的较大者(确保单边路径)
if(!flag || NodeAllowAddValue < NodeRightAllowMaxValue) {
NodeAllowAddValue = NodeRightAllowMaxValue; // 更新为更大的贡献值
if(!flag) flag = true; // 首次记录贡献值
}
}
// 更新全局最大值(当前节点的完整路径和可能包含左右子树)
if(NodeMaxValue > MaxValue) MaxValue = NodeMaxValue;
// 返回当前节点的贡献值(只能选择单边路径)
// 若子节点有正贡献则加上,否则只返回自身值(断开子树)
if(!flag) return root->val; // 无子节点时直接返回自身值
return NodeAllowAddValue > 0 ? root->val + NodeAllowAddValue : root->val;
}
int maxPathSum(TreeNode* root) {
// 初始化全局最大值为最小整数(处理全负数树的情况)
int MaxValue = 1 << 31; // 等价于INT_MIN
// 执行递归遍历整棵树,计算最大路径和
GetOneNodeMaxValue(root, MaxValue);
// 返回最终计算的全局最大路径和
return MaxValue;
}
};