算法day18|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

算法day18|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

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

1.一般性解法

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

注意

else if(left!=NULL&&right==NULL)
        return left;

这里返回的是left,而不是root->left。我们需要返回的是从左孩子传上来的值,而不是左孩子结点。

2.递归法

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

二叉搜索树的另一个利用思路:除了利用二叉树搜索树的中序遍历之外,我们也可以直接利用二叉搜索树在树上的性质:左<中<右。由于没有用到中序遍历的递增序列,所以在递归的时候可以不使用中序遍历,直接用它的性质来接就行了

核心思路:如果结点值 > p和q的值,那么说明p和q在该节点左边,所以需要向左递归;如果结点值 < p和q的值,那么说明p和q在该节点右边,所以需要向右递归;如果节点值在p和q之间,那么这个结点就是最近的公共祖先。

代码细节:如果函数有返回值,那么在if和else之外一定还需要有一个return,所以这样是错的:

else if(root->val<p->val&&root->val<q->val)
        {
            TreeNode*right=traversal(root->right,p,q);
            if(right!=NULL)
            return right;
        }
else
        return root;
    }

但是改成这样就对了,在 if 和 else 之外再加一个return:

else if(root->val<p->val&&root->val<q->val)
        {
            TreeNode*right=traversal(root->right,p,q);
            if(right!=NULL)
            return right;
        }
else
{
     	return root;
}     
		return NULL;
    }

3.迭代法

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root!=NULL)
        {
            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.二叉搜索树中的插入操作

1.递归法

比较简单,代码如下:

class Solution {
public:
    void traversal(TreeNode* &root, int val)
    {
        if(root==nullptr)
        {
            root=new TreeNode(val);
            return;
        }
        if(root->val<val)
        {
            if(root->right)
                traversal(root->right,val);
            else
            {
                TreeNode*node=new TreeNode(val);
                root->right=node;
            }
        }
        if(root->val>val)
        {
            if(root->left)
                traversal(root->left,val);
            else
            {
                TreeNode*node=new TreeNode(val);
                root->left=node;
            }
        }
        return;
    }
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        traversal(root,val);
        return root;
    }
};

**核心思路:**当结点值 > root,且右孩子不为空,则向右递归。若右孩子为空,则直接插入,作为该节点的右孩子;当节点值 < root时同理。

易错:

void traversal(TreeNode* &root, int val)

这里需要“带回去”,所以要加上&。

2.迭代法

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(root==nullptr)
        {
            root=new TreeNode(val);
            return root;
        }
        TreeNode*cur=root;
        TreeNode*parent=cur;
        while (cur != NULL) {
            parent = cur;
            if (cur->val > val) cur = cur->left;
            else 
            cur = cur->right;
        }
        TreeNode*node=new TreeNode(val);
        if(parent->val<val)
        parent->right=node;
        else
        parent->left=node;
        return root;
    }
};

思路与递归法一致。

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

这题难度不小,第一遍尽量理解:

class Solution {
public:
    TreeNode* traversal(TreeNode* root, int key)
    {
        if(root==nullptr)
       return nullptr;
       if(root->val==key)
       {
        if(root->left==nullptr&&root->right==nullptr)
        {
            delete root;
            return nullptr;
        }
        else if(root->left!=nullptr&&root->right==nullptr)
        {
            TreeNode*temp=root->left;
            delete root;
            return temp;
        }
        else if(root->left==nullptr&&root->right!=nullptr)
        {
            TreeNode*temp=root->right;
            delete root;
            return temp;
        }
        else if(root->left!=nullptr&&root->right!=nullptr)
        {
            TreeNode*cur=root->right;
            TreeNode*temp=root->right;
            while(cur->left)
            cur=cur->left;
            cur->left=root->left;
            delete root;
            return temp;
        }
       }
        if(root->val>key)
        root->left=traversal(root->left,key);
        if(root->val<key)
        root->right=traversal(root->right,key);
        return root;
    }
    TreeNode* deleteNode(TreeNode* root, int key) {
       return traversal(root,key);
    }
};

总体思路:

  • 参数和返回值正常

  • 终止条件:

    这题的终止条件是重中之重,因为核心条件的判断也纳入了终止条件,即只要符合某种条件就终止。这个条件就是节点值等于key,因为只要节点值等于key就不用再继续递归了。所以真正删除的核心操作就在终止条件里,一共有4种情况:

    • 左右孩子都空,即为叶节点

    • 左孩子空,右孩子不空

    • 左孩子不空,右孩子空

    • 左右孩子都不空(注意这里可以有两种处理逻辑,只要能满足二叉搜索树的定义即可

  • 单层递归逻辑:不用对当前结点做处理,只有满足一定条件时才会有处理(即终止条件)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值