LeetCode 1026. 节点与其祖先之间的最大差值
题目描述



题意分析
在二叉树中选择具有祖先与后代关系的两个节点,使它们数值之差的绝对值最大。祖先不一定是直接父节点,可以隔着多层;两个节点也不要求包含整棵树的根。
位于不同分支、彼此没有祖先关系的节点不能配成一对。因此整棵树的最大值减最小值未必合法,需要把比较限制在同一条从根向下的路径上。
解法:DFS 维护路径最大最小值
核心思路
[!blue]
一条从根向下的路径上,任意两个不同节点都有祖先关系。对这条路径来说,最大绝对差就是路径最大值减最小值,没必要保存所有祖先再逐一比较。
DFS 向下传递
minVal、maxVal,表示当前路径已经出现过的最小和最大值。进入一个节点时,先把它的值并入两个极值,再把更新后的范围分别传给左右孩子。递归到空孩子时,当前路径前缀已经确定,可以返回
maxVal - minVal。空孩子不一定出现在叶子之后,但这个路径前缀本身仍然合法;继续向其他孩子延伸只会保持或扩大极差,不会让此前贡献变成非法值。左右递归各自给出本分支能达到的最大差,当前层取两者较大值即可。不能把左右极值合并后相减,否则又会混入没有祖先关系的跨分支节点。
每一对合法祖先和后代都处于某条根到叶路径中,而每条路径的极值差又确实来自一对合法节点,所以遍历全部分支后取最大极差,既不会漏掉答案,也不会引入非法配对。
解题步骤
- 代码先处理空根;非空时用根值初始化路径最小值和最大值。
- 到达真实节点后,更新当前路径极值,把该节点纳入范围。
- 用这两个值分别递归左右孩子;空孩子直接返回当前极差。
- 每层返回左右结果中的较大值,最终根调用的返回值就是答案。
代码实现
class Solution {
public int maxAncestorDiff(TreeNode root) {
if (root == null) {
return 0;
}
return dfs(root, root.val, root.val);
}
private int dfs(TreeNode node, int minVal, int maxVal) {
if (node == null) {
return maxVal - minVal;
}
// 先并入当前节点,再把独立的路径极值传给子树。
minVal = Math.min(minVal, node.val);
maxVal = Math.max(maxVal, node.val);
int left = dfs(node.left, minVal, maxVal);
int right = dfs(node.right, minVal, maxVal);
// 只取一条合法路径的最大贡献,不能跨分支配对。
return Math.max(left, right);
}
}
func maxAncestorDiff(root *TreeNode) int {
if root == nil {
return 0
}
var dfs func(node *TreeNode, minVal int, maxVal int) int
dfs = func(node *TreeNode, minVal int, maxVal int) int {
if node == nil {
return maxVal - minVal
}
// 先并入当前节点,再把独立的路径极值传给子树。
if node.Val < minVal {
minVal = node.Val
}
if node.Val > maxVal {
maxVal = node.Val
}
left := dfs(node.Left, minVal, maxVal)
right := dfs(node.Right, minVal, maxVal)
// 只取一条合法路径的最大贡献,不能跨分支配对。
if left > right {
return left
}
return right
}
return dfs(root, root.Val, root.Val)
}
复杂度分析
- 时间复杂度:$O(n)$,每个节点访问一次,更新极值及合并答案都是常数次操作。
- 空间复杂度:$O(h)$,递归栈深度等于树高;链状树最坏为 $O(n)$,没有保存所有祖先的额外列表。
关键点总结
[!green]
- 用路径最大值和最小值压缩祖先信息,足以求该路径的最大绝对差。
- 极值通过数值参数传递,左右分支拿到各自的路径状态,不需要回滚共享变量。
- 分支结果取最大,分支极值不混合,始终保持祖先关系约束。
易错点总结
[!yellow]
- 把整棵树的全局最大值减最小值,可能选中两条不同分支上的节点。
- 只比较父子差值,会漏掉隔着多层的祖先与后代。
- 传给孩子之前不加入当前值,可能漏掉路径中间的关键极值。
- 用不恢复的全局极值保存路径,会把先访问分支的值带入另一分支。
- 将左右返回值相加,不能对应任何一对节点;题目求一个最大差,应取最大值。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 1448. 统计二叉树中好节点的数目 | 中等 | 同样沿根路径下传极值,原题只需祖先最大值,本题同时保留最小与最大值计算最大差。 |
| 112. 路径总和 | 简单 | 同样把路径相关信息作为递归参数,本题传极值,原题传累计和或剩余目标。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!