节点与其祖先之间的最大差值 图解题解
这道题到底在问什么
- 输入
- root=[8,3,10,1,6,null,14,...]
- 输出
- 7(|8−1|=7)
最优解:一步一步想明白
- 3记住「下行传 lo/hi、到叶子算 hi 减 lo 取最大」,下面每帧都在套它。
- 4best = 0开局把最大差 best 记成 0。DFS 从根出发,一路把这条路径的 min、max 带下去。
- 5访问 40从根 40 出发(紫色)。这条路径的 min 和 max 一开始都记成根的值 40。
- 6lo=40, hi=40把 40 纳入这条路径:min 更新为 40、max 更新为 40。它还有孩子,带着新的 min、max 继续往下。
- 7访问 20沿路径走到节点 20(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 40。
- 8lo=20, hi=40把 20 纳入这条路径:min 更新为 20、max 更新为 40。它还有孩子,带着新的 min、max 继续往下。
- 9访问 10沿路径走到节点 10(紫色)。在纳入它之前,这条路径上的 min 是 20、max 是 40。
- 10lo=10, hi=40把 10 纳入这条路径:min 更新为 10、max 更新为 40。它没有孩子,是叶子,下一步算这条路径的极差。
- 11极差 40−10=30到达叶子 10。这条根到叶路径的 max 是 40、min 是 10,极差 = 40 − 10 = 30。
- 12best = 30极差 30 比之前的最大差大,刷新 best = 30(这条路径暂时领先)。
- 13访问 30沿路径走到节点 30(紫色)。在纳入它之前,这条路径上的 min 是 20、max 是 40。
- 14lo=20, hi=40把 30 纳入这条路径:min 更新为 20、max 更新为 40。它没有孩子,是叶子,下一步算这条路径的极差。
- 15极差 40−20=20到达叶子 30。这条根到叶路径的 max 是 40、min 是 20,极差 = 40 − 20 = 20。
- 16best = 30极差 20 没超过当前最大差 30,best 保持不变。
- 17访问 70沿路径走到节点 70(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 40。
- 18lo=40, hi=70把 70 纳入这条路径:min 更新为 40、max 更新为 70。它还有孩子,带着新的 min、max 继续往下。
- 19访问 60沿路径走到节点 60(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 70。
- 20lo=40, hi=70把 60 纳入这条路径:min 更新为 40、max 更新为 70。它没有孩子,是叶子,下一步算这条路径的极差。
- 21极差 70−40=30到达叶子 60。这条根到叶路径的 max 是 70、min 是 40,极差 = 70 − 40 = 30。
- 22best = 30极差 30 没超过当前最大差 30,best 保持不变。
- 23访问 90沿路径走到节点 90(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 70。
- 24lo=40, hi=90把 90 纳入这条路径:min 更新为 40、max 更新为 90。它没有孩子,是叶子,下一步算这条路径的极差。
- 25极差 90−40=50到达叶子 90。这条根到叶路径的 max 是 90、min 是 40,极差 = 90 − 40 = 50。
- 26best = 50极差 50 比之前的最大差大,刷新 best = 50(这条路径暂时领先)。
- 27答案 = 50四条根到叶路径的极差分别是 30、20、30、50,最大的来自 40→70→90 这条(max 90、min 40)。所以答案是 50。整趟只做了一次 DFS、每个节点访问一次。
⚠️ 容易写错的地方
✗ 错:只比较相邻父子两层
✓ 对:祖先包含路径上所有上层节点,要带整条路径的 min/max
最大差可能出现在很远的祖先与后代之间,只看父子会漏
✗ 错:为每个节点向上回溯找所有祖先
✓ 对:下行时把 lo/hi 累积传给孩子,一次 DFS 搞定
逐节点向上找是 O(n·h),没必要;传 min/max 下去是 O(n)
✗ 错:lo、hi 初始化成 0 或极值
✓ 对:从根开始,lo、hi 都先设成根的值
初始化错会让根那一层的差值算错(比如混进一个并不在树里的 0)
完整代码(Python / C++ / Java)
Python
from typing import List, Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def maxAncestorDiff(self, root: Optional[TreeNode]) -> int:
def dfs(node, lo, hi):
if not node:
return hi - lo
lo, hi = min(lo, node.val), max(hi, node.val)
return max(dfs(node.left, lo, hi), dfs(node.right, lo, hi))
return dfs(root, root.val, root.val)C++
#include <algorithm>
#include <climits>
#include <functional>
#include <queue>
#include <vector>
using namespace std;
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) {}
};
class Solution { public: int maxAncestorDiff(TreeNode* root){ function<int(TreeNode*,int,int)> dfs=[&](TreeNode* n,int lo,int hi){ if(!n)return hi-lo; lo=min(lo,n->val); hi=max(hi,n->val); return max(dfs(n->left,lo,hi),dfs(n->right,lo,hi)); }; return dfs(root,root->val,root->val); } };Java
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; }
}
class Solution { public int maxAncestorDiff(TreeNode root){ return dfs(root,root.val,root.val); } int dfs(TreeNode n,int lo,int hi){ if(n==null)return hi-lo; lo=Math.min(lo,n.val); hi=Math.max(hi,n.val); return Math.max(dfs(n.left,lo,hi),dfs(n.right,lo,hi)); } }复杂度
时间
O(n)
每个节点恰好访问一次,常数次比较与取 min/max;n 是节点数
空间
O(h)
只用递归栈,深度等于树高 h;最坏树退化成链时 O(n)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 节点与其祖先之间的最大差值 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么是 O(n) 而不是对每个节点都往上找祖先的 O(n·h)?+
诀窍是「下行传参」:每个节点把更新后的 lo、hi 直接传给左右孩子,孩子拿到的就是它到根这条路径的极值,不必再向上回溯。这样每个节点只被访问一次,总时间 O(n)。
最大差为什么一定是「路径最大值与最小值」这一对,而不是中间某两个?+
因为对同一条路径上的任意两点,它们的差都不会超过这条路径里最大值与最小值的差;而最大值和最小值本身一个是另一个的祖先(同在一条根到叶路径上),正好构成合法的祖先—后代对。所以取每条路径的 max 减 min 就覆盖了所有可能。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 节点与其祖先之间的最大差值 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。