LeetCode 面试题 04.06. 后继者
题目描述

题意分析
返回二叉搜索树中指定节点
p在中序遍历后的下一个节点。搜索树的中序序列严格递增,所以等价于寻找值严格大于p.val的最小节点;如果p已是最大节点,则返回空。
解法:利用 BST 性质定位后继
核心思路
[!blue]
先看p是否有右子树。 中序顺序是左子树、当前节点、右子树,所以访问完p后,如果右子树存在,下一步一定进入右子树。沿它的左孩子不断向下,就能找到其中最先访问、也就是值最小的节点,这就是后继;不能直接认定右孩子就是答案。没有右子树时,后继只能来自祖先:它是从
p向上看,第一个把p放在自己左子树中的祖先。节点没有父指针,可以反过来从根向下搜索,同时用succ保存目前遇到的后继候选。若
cur.val > p.val,当前节点符合“严格更大”,先保存为候选。它的右子树更大,不可能比当前候选更接近p,因此继续去左子树寻找更小的合格值。若cur.val <= p.val,当前节点及整个左子树都不合格,只能去右子树。每次转向都排除不合格节点,或排除不会优于当前候选的节点,因而不会丢失最小的较大值。最终走到空位置时,
succ就是后继;始终未找到大于p的节点时,它保持为空。相等时必须走右侧,不能把p自己记为候选。
解题步骤
- 若 p 有右子树,返回其最左节点。
- 否则从根开始,候选初始化为空。
- 当前节点值大于
p.val时更新候选并向左;否则向右。每轮只进入一个子树。- 走到空位置后返回候选。最大节点没有右子树,搜索过程中也不会产生候选,正好返回空。
代码实现
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
// 存在右子树时,中序下一节点是该子树的最左节点。
if (p.right != null) {
return leftMost(p.right);
}
TreeNode succ = null;
TreeNode cur = root;
while (cur != null) {
if (p.val < cur.val) {
// 当前节点是候选,继续向左寻找更小但仍大于目标的值。
succ = cur;
cur = cur.left;
} else {
cur = cur.right;
}
}
return succ;
}
private TreeNode leftMost(TreeNode node) {
while (node.left != null) {
node = node.left;
}
return node;
}
}
func inorderSuccessor(root *TreeNode, p *TreeNode) *TreeNode {
// 存在右子树时,中序下一节点是该子树的最左节点。
if p.Right != nil {
return leftMost(p.Right)
}
var succ *TreeNode
cur := root
for cur != nil {
if p.Val < cur.Val {
// 当前节点是候选,继续向左寻找更小但仍大于目标的值。
succ = cur
cur = cur.Left
} else {
cur = cur.Right
}
}
return succ
}
func leftMost(node *TreeNode) *TreeNode {
for node.Left != nil {
node = node.Left
}
return node
}
复杂度分析
- 时间复杂度:$O(h)$,其中 $h$ 为树高。无论寻找右子树最左节点还是从根寻找候选,都只沿一条下降路径;平衡时为 $O(\log n)$,退化成链时为 $O(n)$。
- 空间复杂度:$O(1)$。
关键点总结
[!green]
- 后继必须严格更大,不能返回 p 自己。
- 记录候选后还要向左寻找更接近的值。
- 无后继使用空指针表示,不创建虚假节点。
易错点总结
[!yellow]
- 比较使用小于等于:遇到 p 时会把自己记录为后继。
- 有右子树就直接返回右孩子:右孩子的左侧还可能有更小节点。
- 候选初始化为根:最大节点可能错误返回一个无关节点。
- 保存候选后转向右侧:会寻找更大的值而非更小后继。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 173. 二叉搜索树迭代器 | 中等 | 中序迭代器能够依次取得后继,本题只查询一次,直接沿 BST 查找无需展开整个序列。 |
| 230. 二叉搜索树中第 K 小的元素 | 中等 | 同样利用 BST 中序升序性质,第 k 小还需要统计遍历位置,本题用目标值直接导航。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!