1、题目:面试题 04.06. 后继者
设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。如果指定节点没有对应的“下一个”节点,则返回null
。
示例1:
输入: root = [2,1,3], p = 1
2
/ \
1 3输出: 2
示例2:
输入: root = [5,3,6,2,4,null,null,1], p = 6
5
/ \
3 6
/ \
2 4
/
1输出: null
2、补充知识:
(1)先序遍历
代码:
public void dfs(TreeNode root) {
if (root == null) return;
System.out.println(root.val);
dfs(root.left);
dfs(root.right);
}
输入:[5,3,6,2,4,null,null,1]
输出:[5, 3, 2, 1, 4, 6]
(2)中序遍历
代码:
public void dfs(TreeNode root) {
if (root == null) return;
dfs(root.left);
System.out.println(root.val);
dfs(root.right);
}
输入:[5,3,6,2,4,null,null,1]
输出:[1, 2, 3, 4, 5, 6]
(3)后续遍历
代码:
public void dfs(TreeNode root) {
if (root == null) return;
dfs(root.left);
dfs(root.right);
System.out.println(root.val);
}
输入:[5,3,6,2,4,null,null,1]
输出:[1, 2, 4, 3, 6, 5]
(4)二叉搜索树的性质
二叉搜索树又称二叉排序树,它可以是一棵空树。
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
3、中序遍历
-
思路:
利用中序遍历的方法,依次遍历二叉树,找出p节点的下一个节点。
-
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode p, res;
private boolean isReturn;
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
this.p = p;
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if (root == null) return;
dfs(root.left);
if (isReturn && res == null) {
res = root;
}
if (p == root) {
isReturn = true;
}
dfs(root.right);
}
}
4、利用二叉搜索树的性质
-
思路:
利用二产搜索树的性质,左子节点的值始终小于根节点,右子节点的值始终大于根节点,中序遍历的结果就是将所有值从小到大排序。
所以,我们只需要找到比p节点的值大的第一个节点就可以了。
-
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
TreeNode res = null;
// 若p节点有右子节点的时候, 说明目标节点就在右子树的最小值的那个节点上
if (p.right != null) {
// 获取p节点的右子节点
res = p.right;
// 获取右子树的最小值的节点
while (res.left != null) {
res = res.left;
}
return res;
}
// 当p节点没有右子树的时候, 目标节点就不能用上面的方法查找了
while (root != null) {
// 当前节点的值大于p节点的值, 说明该节点可能是目标节点,
// 仍需继续查找是否有比当前节点的值小且大于p节点值的节点
if (root.val > p.val) {
// 当前节点可能是目标节点, 先将当前节点赋予res,
// 如果后面遍历还能找到更符合要求的节点就将新节点赋予res,
// 如果没有, 则说明当前节点就是目标节点
res = root;
root = root.left;
} else {
// 当前节点的值大于p节点的值, 就向比当前节点值大的方向遍历
root = root.right;
}
}
// 当root为null时会返回null, 所以不需要判断
return res;
}
}