面试题 04.06. 后继者

面试题 04.06. 后继者 - 力扣(LeetCode)
在这里插入图片描述

这儿的后继是指二叉搜索树按照中序遍历的后继(中序后继),也就是说节点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;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值