这儿的后继是指二叉搜索树按照中序遍历的后继(中序后继),也就是说节点x的后继是中序遍历的顺序中节点x的下一个节点。
借助外部空间
那既然是中序遍历,简单的思路就是进行一遍中序遍历,把元素按顺序导入数组,最后在数组里面进行查找。
class Solution {
public:
void inorder(TreeNode* root, vector<TreeNode*> &vec){
if(root->left)
inorder(root->left, vec);
vec.push_back(root);
if(root->right)
inorder(root->right, vec);
}
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(!root) return NULL;
vector<TreeNode*> vec;
inorder(root, vec);
auto it = find(vec.begin(), vec.end(), p);
return (++it != vec.end()) ? *(it) : NULL;
}
};
另一种更好的方法,绝大部分情况不用遍历全部节点:
还记得之前写的中序遍历,主要分为递归写法和迭代写法(借助栈空间):LeetCode第 94 题:二叉树的中序遍历(C++)
迭代写法的基本思想就是借助栈先进后出的特点,如果我们依次pop(),如果某个时刻pop()出来的节点值刚好是指定节点值,那么此刻栈顶元素就是要求的后继。
class Solution {
public:
//中序遍历迭代法
TreeNode* inorder(TreeNode* root, TreeNode* p){
stack<TreeNode*> stk;
auto cur = root;
bool flag = false;
while(cur || !stk.empty()){
while(cur){
stk.push(cur);
cur = cur->left;
}
if(flag) return stk.top();
cur = stk.top();
stk.pop();
if(cur->val == p->val) flag = true; //下一轮push之后的栈顶元素即为后继
cur = cur->right;
}
return NULL;
}
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(!root || !p) return NULL;
return inorder(root, p);
}
};
递归遍历查找后继(不借助外部空间)
遍历规则:
1、如果节点p的值大于等于root的值,那么节点p的后继在root的右子树中(最小的值),到右子树里面递归。比如这样:
2、如果节点p的值小于root的值,说明节点p在root的左子树中,它的后继分两种情况:
- 如果在左子树中找到了后继节点,直接返回答案;
- 如果在左子树中没有找到后继节点,那就是p的右子树为空,root就是它的后继。
emmm…不过感觉这个代码还是蛮抽象的。。。
class Solution {
public:
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(!root || !p) return NULL;
if(p->val >= root->val)
return inorderSuccessor(root->right, p);
else{
auto left = inorderSuccessor(root->left, p);
return left ? left : root;
}
}
};