题目描述
思路解析动画文字版
每到一个节点再回头看祖先会重复。
DFS 时带着 pathMax,节点值 ≥ pathMax 就计数,并把新的最大值传给孩子。
① 好节点=从根到它的路径上没有更大的值:带着「这条路径的最大值」往下递归;当前值 ≥ path_max 就是好节点。
② 根 3:3 ≥ path_max(3) → 好节点 ✓:根是路径起点、没有祖先,自己就是路径最大值,必然好节点。计数 1。
③ 左子 1:1 < path_max(3) → 不是好节点:走到左子 1,路径最大仍是 3;1 比 3 小 → 路上有人挡着,不算好节点。
④ 1 的左子 3:3 ≥ 3 → 好节点 ✓(相等也算):深入到这个 3,路径最大还是 3,3 ≥ 3 → 好节点。相等也算好,计数 2。
⑤ 右子 4:4 ≥ 3 → 好 ✓,path_max 更新为 4:回到根的右子 4,4 ≥ 3 → 好节点,计数 3;并把 path_max 更新成 4 带给它的子树。
一句话记住:DFS 时带着 pathMax,节点值 ≥ pathMax 就计数,并把新的最大值传给孩子。
边界三连:本题真边界:单根、递增链、递减链。
⑥ 4 的子树 & 为何 path_max 要按「各自路径」下传:4 的右子 5 ≥ 4 → 好(计数 4),左子 1 < 4 → 不是。关键:path_max 是「每条根→当前的路径」各自的最大值,换分支要用该分支的值、不能用全局最大。答案 = 4。
面试追问 · 核心思路:思路:DFS 带 path_max,node.val ≥ path_max 即好,更新后下传。
面试追问 · 回溯为何无需手动恢复:path_max 按值传参,每层有独立副本,天然隔离。
面试追问 · 复杂度:复杂度:每点访问一次 O(n),递归栈 O(h)。
这题学完别乱跳,去 /leetcode-animation/ds?k=tree 连刷同类树形 DFS;卡住时用 AI 答疑问「path_max 该怎么随递归下传」。
参考代码
class Solution: def goodNodes(self, root): def dfs(node, path_max): if not node: return 0 good = 1 if node.val >= path_max else 0 path_max = max(path_max, node.val) return good + dfs(node.left, path_max) + dfs(node.right, path_max) return dfs(root, root.val)复杂度
- 时间复杂度:O(n),每个节点恰好访问一次
- 空间复杂度:O(h),递归栈深度=树高 h(最坏退化成链 O(n))
可套用的代码模板
记牢:DFS 带 path_max,node.val ≥ path_max 即好,max 更新后下传左右子树。
Python
# 路径最大值 DFS 骨架def dfs(node, path_max): if not node: return 0 good = 1 if node.val >= path_max else 0 # ≥ 即好节点 path_max = max(path_max, node.val) # 更新后下传 return good + dfs(node.left, path_max) + dfs(node.right, path_max)return dfs(root, root.val) # 初值=根,根必好易错点
面试追问把动画讲成自己的话
追问整体思路是什么?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
验证二叉搜索树
LeetCode 98 · 中等 · 沿着 树 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题