LeetCode 865. 具有所有最深节点的最小子树
题目描述


题意分析
找出一棵子树,包含原树中深度最大的全部节点,并且它的范围尽可能小,返回它的根节点。子树必须连同根的全部后代一起取,不能任意挑选几个节点;所求根就是所有最深节点的最近公共祖先。
解法:后序递归合并高度与答案
核心思路
[!blue]
当前子树的最深节点来自哪一侧,取决于左右子树的高度。因此采用后序遍历,先得到两侧结果,再把高度和答案一起合并,避免先遍历找最深层、再重新寻找公共祖先。
递归返回的
Result包含两个量:depth是这棵子树的高度,空树为 0、叶子为 1;node是包含这棵子树全部最深节点的最小子树根。这里的depth是相对子树根计算的高度,不是节点在原树中的绝对深度。若左右高度相等且非零,当前子树的最深节点同时出现在两侧。任何位于当前节点下方的子树都只能覆盖其中一侧,所以最近公共祖先只能是当前节点。若两侧都为空,当前节点自己就是唯一最深节点,同样返回自己。
若左右高度不同,较浅一侧没有当前子树的最深节点,全部目标都在较深一侧。该侧递归已经找到包含它们的最小子树,直接沿用它的
node即可,不能退回到该侧的根。无论答案来自哪里,向父层报告的高度都是max(left.depth, right.depth) + 1。这样每次合并都同时保持高度正确、答案范围最小,处理到原根后,返回的
node就覆盖全树全部最深节点。
解题步骤
- 空节点返回空答案与零高度。
- 递归取得左右子树的答案与高度。
- 等高返回当前节点,否则沿用更深一侧的答案。
- 高度增加一,顶层取返回的答案节点。
只有一个最深节点时,答案就是这个节点本身;上层会不断沿用该答案。整棵树只有根节点时,也由左右空树等高的分支直接处理。
代码实现
class Solution {
public TreeNode subtreeWithAllDeepest(TreeNode root) {
return dfs(root).node;
}
private Result dfs(TreeNode node) {
if (node == null) {
return new Result(null, 0);
}
Result left = dfs(node.left);
Result right = dfs(node.right);
// 左右等深时答案在当前节点;两侧皆空时覆盖叶子情形。
if (left.depth == right.depth) {
return new Result(node, left.depth + 1);
}
if (left.depth > right.depth) {
return new Result(left.node, left.depth + 1);
}
return new Result(right.node, right.depth + 1);
}
private static class Result {
TreeNode node;
int depth;
Result(TreeNode node, int depth) {
this.node = node;
this.depth = depth;
}
}
}
type result struct {
node *TreeNode
depth int
}
func subtreeWithAllDeepest(root *TreeNode) *TreeNode {
return dfs(root).node
}
func dfs(node *TreeNode) result {
if node == nil {
return result{nil, 0}
}
left := dfs(node.Left)
right := dfs(node.Right)
// 两侧一样深:最深节点分布在两侧;叶子两侧皆空时也返回自身。
if left.depth == right.depth {
return result{node, left.depth + 1}
}
// 一侧更深:最深节点全在那一侧,直接上传该侧算出的答案节点。
if left.depth > right.depth {
return result{left.node, left.depth + 1}
}
return result{right.node, right.depth + 1}
}
复杂度分析
- 时间复杂度:$O(n)$,每个节点计算一次。
- 空间复杂度:$O(h)$,递归栈及活跃返回值由树高决定。
关键点总结
[!green]
- 高度用于决定方向,答案节点用于保留更深层的公共祖先。
- 更深一侧的答案不一定就是它的根。
- 叶子由左右等高分支统一处理。
易错点总结
[!yellow]
- 一侧更深时直接返回那个孩子:最深节点的公共祖先可能还在更下方。
- 只返回较大高度而丢掉答案节点:无法把已求出的最小子树上传。
- 只比较节点值:最深与大小无关。
- 把最小子树理解成任意最小叶子:必须同时包含全部最深节点。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 236. 二叉树的最近公共祖先 | 中等 | 可把所有最深节点不断合并为最近公共祖先,本题用后序同时返回深度与祖先候选更直接。 |
| 104. 二叉树的最大深度 | 简单 | 子树高度是判断最深节点落在哪一侧的基础,两侧同高时当前节点就是候选。 |
| 1123. 最深叶节点的最近公共祖先 | 中等 | 递归向上传递目标命中信息;本题定位包含所有最深节点的最小子树,该题合并最深层深度与祖先信息。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!