一、题目描述
给定一棵二叉搜索树和其中的一个节点 p ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null 。
节点 p 的后继是值比 p.val 大的节点中键值最小的节点,即按中序遍历的顺序节点 p 的下一个节点。
输入:root = [2,1,3], p = 1
输出:2
解释:这里 1 的中序后继是 2。请注意 p 和返回值都应是 TreeNode 类型。
二、代码思路
中序遍历,在中序遍历的时候维护两个节点,一个是当前访问的节点,一个是当前访问节点的上一个节点。
如果上一个prev节点iu是目标节点,那么当前节点就是目标节点的中序遍历后继。
最好使用,非递归的中序遍历,这样找到prev之后,很容易返回。递归形式的中序遍历,不好记录上一个节点和下一个节点。
三、代码题解
非递归形式中序遍历:
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
TreeNode prev = null, curr = root;
while (!stack.isEmpty() || curr != null) {
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
if (prev == p) {
return curr;
}
prev = curr;
curr = curr.right;
}
return null;
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode curNode;
private TreeNode preNode;
private TreeNode target;
private TreeNode res;
private TreeNode firstNode;
private int flag = 0;
private void dfs(TreeNode node, TreeNode preNode) {
if (node == null) return;
dfs(node.left, preNode);
curNode = node;
if (preNode == target) {
res = curNode;
} else {
preNode = node;
}
dfs(node.right,curNode);
}
//获取树的最左节点
private TreeNode getFirstNode(TreeNode root) {
while (true) {
if (root.left != null) {
root = root.left;
continue;
}
if (root.right != null) {
root = root.right;
continue;
}
if (root.left == null && root.right == null) {
return root;
}
}
}
private TreeNode getFirstNode1(TreeNode node) {
TreeNode left = null;
TreeNode right = null;
if (node == null) return null;
if (node.left != null) {
left = getFirstNode(node.left);
} else if (node.right != null) {
right = getFirstNode(node.right);
}
if (left == null && right == null && flag == 0) {
flag = 1;
firstNode = node;
return node;
}
return null;
}
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
//二叉搜索树:类似于二分,能够优化排序。
//在二叉搜索树中某个节点的后继:可以理解为该节点中序遍历之后的下一个节点,而且这节点是大于该节点中最小的节点。
//所以我们可以采用 双指针 + 中序遍历的手段,双指针分别标记当前节点和下一个节点。
this.target = p;
getFirstNode(root);
dfs(root, firstNode);
return res;
}
}
C语言版递归找下一个节点:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Successor {
public:
//中序遍历函数
void ldr_erach(TreeNode *root, int p, int &post, int &val)
{
if (root == NULL) return ;
ldr_erach(root->left, p, post,val); //根据中序遍历的顺序,只要p匹配上那么下一个就是我们要找的值
if (1 == post) //直接用val的引用接收,post作为标志位也要用引用去改变
{ //找到了就把post改成1,接收完后改成-1这样两个条件就不会触发
val = root->val;
post = -1;
}
else if (0 == post && p == root->val)
{
post=1;
}
ldr_erach(root->right, p, post, val);
}
int findSucc(TreeNode* root, int p) {
// write code here
int val = 0,post = 0;
ldr_erach(root, p, post, val);
return val;
}
};
java版递归找后继:
package leetcode;
/*
* @author lzy
* @version 1.0
* */
public class treeFindNext {
public static void main(String[] args) {
TreeNode root = new TreeNode(2);
TreeNode node1 = new TreeNode(1);
TreeNode node2 = new TreeNode(3);
root.left = node1;
root.right = node2;
inorderSuccessor(root,node1);
}
private static TreeNode res;
public static void dfs(TreeNode node, int post, TreeNode p) {
if (node == null) return;
dfs(node.left, post, p);
if (post == 1) {
res = node;
post = -1;
} else if (post == 0 && node == p) {
post = 1;
}
dfs(node.right, post, p);
}
public static TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
dfs(root, 0, p);
return res;
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
由于Java中只有值传递这样的概念,所以其实上一层post修改之后,不会影响到下一层。