题目描述
思路解析动画文字版
记住「下行传 lo/hi、到叶子算 hi 减 lo 取最大」,下面每帧都在套它。
准备 · 从根出发:开局把最大差 best 记成 0。DFS 从根出发,一路把这条路径的 min、max 带下去。
下行 · 到达 40:从根 40 出发(紫色)。这条路径的 min 和 max 一开始都记成根的值 40。
纳入 40:把 40 纳入这条路径:min 更新为 40、max 更新为 40。它还有孩子,带着新的 min、max 继续往下。
下行 · 到达 20:沿路径走到节点 20(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 40。
纳入 20:把 20 纳入这条路径:min 更新为 20、max 更新为 40。它还有孩子,带着新的 min、max 继续往下。
下行 · 到达 10:沿路径走到节点 10(紫色)。在纳入它之前,这条路径上的 min 是 20、max 是 40。
纳入 10:把 10 纳入这条路径:min 更新为 10、max 更新为 40。它没有孩子,是叶子,下一步算这条路径的极差。
叶子 10 · 算极差:到达叶子 10。这条根到叶路径的 max 是 40、min 是 10,极差 = 40 − 10 = 30。
叶子 10 · 刷新 best:极差 30 比之前的最大差大,刷新 best = 30(这条路径暂时领先)。
下行 · 到达 30:沿路径走到节点 30(紫色)。在纳入它之前,这条路径上的 min 是 20、max 是 40。
纳入 30:把 30 纳入这条路径:min 更新为 20、max 更新为 40。它没有孩子,是叶子,下一步算这条路径的极差。
叶子 30 · 算极差:到达叶子 30。这条根到叶路径的 max 是 40、min 是 20,极差 = 40 − 20 = 20。
叶子 30 · best 不变:极差 20 没超过当前最大差 30,best 保持不变。
下行 · 到达 70:沿路径走到节点 70(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 40。
纳入 70:把 70 纳入这条路径:min 更新为 40、max 更新为 70。它还有孩子,带着新的 min、max 继续往下。
下行 · 到达 60:沿路径走到节点 60(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 70。
纳入 60:把 60 纳入这条路径:min 更新为 40、max 更新为 70。它没有孩子,是叶子,下一步算这条路径的极差。
叶子 60 · 算极差:到达叶子 60。这条根到叶路径的 max 是 70、min 是 40,极差 = 70 − 40 = 30。
叶子 60 · best 不变:极差 30 没超过当前最大差 30,best 保持不变。
下行 · 到达 90:沿路径走到节点 90(紫色)。在纳入它之前,这条路径上的 min 是 40、max 是 70。
纳入 90:把 90 纳入这条路径:min 更新为 40、max 更新为 90。它没有孩子,是叶子,下一步算这条路径的极差。
叶子 90 · 算极差:到达叶子 90。这条根到叶路径的 max 是 90、min 是 40,极差 = 90 − 40 = 50。
叶子 90 · 刷新 best:极差 50 比之前的最大差大,刷新 best = 50(这条路径暂时领先)。
完成:四条根到叶路径的极差分别是 30、20、30、50,最大的来自 40→70→90 这条(max 90、min 40)。所以答案是 50。整趟只做了一次 DFS、每个节点访问一次。
边界:单节点 0、全等 0、链就是首尾极差。
面试重点:下行传 min/max 做到 O(n);最大差必出现在路径极值这一对。
参考代码
from typing import List, Optionalclass TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = rightclass 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)复杂度
- 时间:O(n),每个节点恰好访问一次,常数次比较与取 min/max;n 是节点数
- 空间:O(h),只用递归栈,深度等于树高 h;最坏树退化成链时 O(n)
易错点
面试追问把动画讲成自己的话
追问为什么是 O(n) 而不是对每个节点都往上找祖先的 O(n·h)?
追问最大差为什么一定是「路径最大值与最小值」这一对,而不是中间某两个?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
删点成林
LeetCode 1110 · 中等 · 沿着 树套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题