LeetCode 124. 二叉树中的最大路径和
本节目标
向父节点只返回单边最大贡献,在当前节点组合左右贡献更新完整路径答案。
这是树上综合问题中区分“向上返回值”和“完整答案”的典型树形 DP。
题意与边界
路径由不同节点间的父子边连接,至少包含一个节点,不要求经过根,也不要求从根到叶。节点值可以为负,因此全负树的答案是值最大的单个节点,而不是空路径的 0。
单边贡献与完整路径
dfs(node) 向父节点返回“从 node 出发且只能选择一侧向下延伸”的最大贡献。父节点无法同时接住当前节点的左右两条边,否则路径会分叉。负贡献不如不选,故左右返回值都先与 0 取最大值。
但经过当前节点的完整候选路径可以同时使用左右贡献,值为 node.val + left + right,用全局答案更新。向上返回时只保留 node.val + max(left, right)。入口必须重置答案,避免复用同一对象时保留上一棵树的结果。
正确性依据
任意简单路径有唯一最高节点。该节点以下的路径至多各从左、右子树选一条连续分支,递归计算出的非负贡献正是每侧最优选择,故当前候选覆盖所有以该节点为最高点的路径。遍历所有节点并取最大值不会漏解;只返回一条分支又保证父节点得到的是连续可延伸路径。
代码实现
- C++
- Python
C++17
class Solution {
public:
int maxPathSum(TreeNode* root) {
answer = std::numeric_limits<int>::min();
dfs(root);
return answer;
}
private:
int answer;
int dfs(TreeNode* node) {
if (node == nullptr) {
return 0;
}
int left = std::max(0, dfs(node->left));
int right = std::max(0, dfs(node->right));
answer = std::max(answer, node->val + left + right);
return node->val + std::max(left, right);
}
};
Python 3
from typing import Optional
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
self.answer = float('-inf')
def dfs(node):
if node is None:
return 0
left = max(0, dfs(node.left))
right = max(0, dfs(node.right))
self.answer = max(self.answer, node.val + left + right)
return node.val + max(left, right)
dfs(root)
return self.answer
复杂度分析
每个节点访问一次,时间复杂度为 O(n);递归栈深度为 O(h),其中 h 为树高。
边界与易错点
- 把左右贡献之和返回给父节点,会形成分叉而非一条路径。
- 不丢弃负贡献,会让可选路径变差。
- 用
0初始化答案会错误处理全负树。 - 忘记在入口重置答案,会污染下一次调用。
模式迁移
直径也在当前节点组合左右信息,但它向上返回高度;遇到“当前节点组合完整结果、父节点只取单边”的题目,应把这两个量分别命名和证明。