day22|LeetCode:● 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点

题目链接:235. 二叉搜索树的最近公共祖先

一:思路:

因为BST的特性,当左子树出现结点p,右子树出现了结点q,或者 左子树出现结点q,右子树出现节点p,那他必定是最近公共祖先,找到这个点向上返回结果就可以了。

二.递归法

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) || (root->val) <= (p->val) && (root->val) >= (q->val)) {
            return root;
        }
        TreeNode* left = traversal(root->left, p, q);
        if (left != NULL) return left;
        TreeNode* right = traversal(root->right,p, q);
        if (left != NULL ) return left;
        else return right;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
         return traversal(root, p, q);
    }
};

三.递归三部曲

1.确定返回类型和参数类型:返回类型为结点类型,为最小公共祖先

2.确定终止条件:当遇到空节点说明没有找到,返回空到上一层,当发现符合在中间的原则,说明找到了,就返回这个结点。步步向上返回

3.确定单层递归的逻辑:先写出遍历,因为返回类型是结点型的,如果下一层返回不为空,就找到了就步步返回。

流程:先不断向左遍历,当遍历到结果时,就返回上一层到递归函数,把结果赋值给left或right,如果,如果有结果了就说明找到了,就不需要继续遍历了,向上返回left和right,一直return结果就行了。

四.总结

返回结点的类型,如果是返回单个结点,找到这个结向上返回就行了,如果是修改添加返回根节点,就需要遍历构造二叉树,用root->left/right=递归函数来进行。


题目链接:450. 删除二叉搜索树中的节点

一.思路

其实可以不考虑题目中提示所说的改变树的结构的插入方式。只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了,因为按照搜索二叉树规则遍历后面一定可以遍历到空结点在那里插入就行了。

例如插入元素10 ,需要找到末尾节点插入便可,一样的道理来插入元素15,插入元素0,插入元素6,需要调整二叉树的结构么? 并不需要。

只要遍历二叉搜索树,找到空节点 插入元素就可以了,那么这道题其实就简单了。

接下来就是遍历二叉搜索树的过程了。

2.递归法

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

三.搜素二叉树特性

当遍历到一个BTS时,因为中间结点比左结点大,比右结点小,所以可以每次判断走右边还是走左边。遇到错误路就不会遍历了,减少了大量时间。这样会走一条正确的路找到空结点插入进去。

这样可以不用遍历整棵二叉树,且找到正确的路径和结点来。

        if (target < root->val) root->left = traversal(root->left, target);
        if (target > root->val) root->right = traversal(root->right, target);

四.递归三部曲

1.确定返回类型和参数类型:返回整棵二叉树的根结点,所以返回treenode结点类型

2.确定终止条件,因为是遍历的正确路径,当遇到空结点时就是我们需要插入的位置了,定义一个结点,返回

3.确定单层递归的逻辑:因为返回类型为结点型,又因为是反会后更改的树根结点,所以root->left/right = 递归函数,最后再返回root,就可以返回整棵二叉树了。

到这里,大家应该能感受到,如何通过递归函数返回值完成了新加入节点的父子关系赋值操作了,下一层将加入节点返回,本层用root->left或者root->right将其接住


题目链接:450. 删除二叉搜索树中的节点

一.思路

删除二叉搜索树的结点,遍历二叉树,找到那个结点并删除,再重新连接二叉树,这题也需要充分使用搜索二叉树的特点。

删除二叉树会遇到的五种情况:

有以下五种情况:

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。

 二.递归法

class Solution {
public:
    TreeNode* traversal(TreeNode* root, int key) {
        //第一种情况,没找到遍历的点就直接返回了
        if (root == NULL) return NULL;
        if (root->val == key) {
           //第二种情况,找到叶子结点,就返回该叶子结点
           if (root->left == NULL && root->right == NULL) return NULL;
           // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
           else if (root->left != NULL && root->right == NULL) return root->left;
           // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
           else if (root->left == NULL && root->right != NULL) return root->right;
             // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
            // 并返回删除节点右孩子为新的根节点。
           else if (root->left != NULL && root->right != NULL) {
               TreeNode* cur = root->right;//定义一个遍历结点
               while(cur->left) {//找到到最左边的结点
                 cur = cur->left;
               }
               cur->left = root->left;插入
               return root->right;//返回新根
           }
        }
       if (key < root->val) root->left = traversal(root->left, key);
       if (key > root->val) root->right = traversal(root->right, key);
       return root;
    }
    TreeNode* deleteNode(TreeNode* root, int key) {
        return traversal(root, key);
    }
};

三.递归三部曲

1.确定返回类型和参数类型:因为要求删除后的新二叉树的根,所以返回类型为TreeNode,

2.确定终止条件:终止条件一般相当于前序遍历,遍历每一个点,当遍历到目标结点后就处理该结点,返回到递归函数

3.确定单层递归逻辑:用搜索二叉树性质遍历二叉树。可以更快的找到正确路径。因为返回根节点,当找到后经过处理后把结果返回到递归函数种连接到上一结点的左子树或右子树,遍历完左子树和右子树,且左子树和右子树都赋值完了,就返回据步根结点,再到上一层的左边或右边,直到返回最终根节点。

四.总结

1.终止条件的遍历顺序是前序遍历,

2,返回到递归函数是确定根的左子树和右子树,最后返回根。

3.明白二叉搜索树,明白递归前的if是防止遍历完全部结点找到一个正确结点加快速度。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值