代码随想录算法训练营第十七天|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

普通的想法是:回溯算法从底往上找。但这是搜索树,所以我们的序列是有序的。所以中结点一定大于p而小于q,或者中结点大于q而小于p。

所以在搜索树中,我们可以从上往下遍历,并且只取最早碰到的节点数,这一定是两个子结点的最大祖先。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL) return root;
        if(root->val>p->val && root->val>q->val){ 
            TreeNode* left = lowestCommonAncestor(root->left, p, q);
            if(left!=NULL) return left;
        }
        if(root->val<p->val && root->val<q->val){
            TreeNode* right = lowestCommonAncestor(root->right, p, q);
            if(right!=NULL) return right;
        }
        return root; //return the first node that between p and q
    }
};

用迭代法也很简单,不用构造stack或者queue:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root){
            if(root->val<p->val && root->val<q->val){
                root = root->left;
            }else if(root->val>p->val && root->val>q->val){
                root = root->right;
            }else{
                return root;
            }
        }
        return NULL;
    }
};

701.二叉搜索树中的插入操作

有多种有效的插入方式,还可以重构二叉搜索树,其实可以不考虑题目中提示所说的改变树的结构的插入方式。

终止条件就是找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。

if (root == NULL) {
    TreeNode* node = new TreeNode(val);
    return node;
}

把添加的节点返回给上一层,就完成了父子节点的赋值操作了。

由于这是搜索树,所以只用搜索一个边,而当寻找到这个边的叶子结点的时候,就可以插入。

此题的终止条件是插入一个数(个人觉得难想到)。

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(root==NULL){
            TreeNode* newval = new TreeNode(val);
            return newval;
        }
        if(root->val>val) root->left = insertIntoBST(root->left, val); //向root的左边插入
        if(root->val<val) root->right = insertIntoBST(root->right, val); //向root的右边插入
        return root;
    }
};

450.删除二叉搜索树中的节点

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

这道题比较复杂:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(root==NULL) return root; //没找到key,直接返回
        //接下来考虑所有找到key的情况
        if(root->val == key){
            if(root->left==NULL && root->right == NULL){
                delete root;
                return NULL;
            }else if(root->left!=NULL && root->right == NULL){
                //因为要将root的空间删除,所以构建一个新的node
                TreeNode* node = root->left;
                delete root;
                return node;
            }else if(root->left==NULL && root->right != NULL){
                //因为要将root的空间删除,所以构建一个新的node
                TreeNode* node = root->right;
                delete root;
                return node;
            }else{
                //左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
                //找到右子树的最左孩子
                TreeNode* cur = root->right;
                while(cur->left!=NULL){
                    cur = cur->left;
                }
                cur->left = root->left;
                //需要重新返回root本来的right的结点,因为这个结点变成了母结点
                TreeNode* node = root->right;
                delete root;
                return node;
            }
        } 
        //搜索树的过程,向左删除,和向右删除。理解为把新的结点返回给上一层
        if(root->val > key) root->left = deleteNode(root->left, key);
        if(root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

注意这一道题和上一道题对数搜索的流程,我们都是通过把新的结点返回给上一层来完成的。

而在235的题目中,我们直接返回了root的左节点/右结点,是因为我们需要向下寻找,而不需要把节点返回给之前的结点。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值