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


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

    讲解:

    回忆一下递归的三部曲,以这题为例。
    1、参数:

    • 当前节点和两个节点。
    Treenode* cur, Treenode*p, Treenode*q
    
    • 1

    2、递归终止条件:
    遇到空返回就可以

    if (cur==NULL) return cur;
    
    • 1

    3、确定单层递归逻辑

    • 遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭又闭)那么如果 cur->val 大于 p->val,同时 cur->val 大于q->val,那么就应该向左遍历(说明目标区间在左子树上)。需要注意的是此时不知道p和q谁大,所以两个都要判断。
    if (cur->val > p->val && cur->val > q->val) {
        TreeNode* left = traversal(cur->left, p, q);
        if (left != NULL) {
            return left;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    同理右边搜索也是一样。

    所以本题的整体代码如下:

    class Solution {
    private:
        TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q){
            if(cur->val > p->val & cur->val > q->val){
                TreeNode* left = traversal(cur->left, p, q);
                if (left!=NULL){
                    return left;
                }
            }
    
            if(cur->val < p->val & cur->val < q->val){
                TreeNode* right = traversal(cur->right, p, q);
                if (right!=NULL){
                    return right;
                }
            }
            return cur;
        }
    
    
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            return traversal(root, p, q);
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

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

    讲解:https://programmercarl.com/0701.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E6%8F%92%E5%85%A5%E6%93%8D%E4%BD%9C.html

    不停向尾部插入节点,当遍历到空节点时就是叶子节点,这时候申请一个新节点存放插入值。

    class Solution {
    public:
        TreeNode* insertIntoBST(TreeNode* root, int val) {
            if (root == NULL) {
                TreeNode* node = new TreeNode(val);
                return node;
            }
            if (root->val > val) root->left = insertIntoBST(root->left, val);
            if (root->val < val) root->right = insertIntoBST(root->right, val);
    
            return root;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    450、删除

    二叉搜索树中的节点

    讲解:https://programmercarl.com/0450.%E5%88%A0%E9%99%A4%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html

    递归三部曲。
    理解一下此题的动画过程,第五种情况。
    在这里插入图片描述

    class Solution {
    public:
        TreeNode* deleteNode(TreeNode* root, int key) {
            if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
            if (root->val == key) {
                // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
                if (root->left == nullptr && root->right == nullptr) {
                    ///! 内存释放
                    delete root;
                    return nullptr;
                }
                // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
                else if (root->left == nullptr) {
                    auto retNode = root->right;
                    ///! 内存释放
                    delete root;
                    return retNode;
                }
                // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
                else if (root->right == nullptr) {
                    auto retNode = root->left;
                    ///! 内存释放
                    delete root;
                    return retNode;
                }
                // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
                // 并返回删除节点右孩子为新的根节点。
                else {
                    TreeNode* cur = root->right; // 找右子树最左面的节点
                    while(cur->left != nullptr) {
                        cur = cur->left;
                    }
                    cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                    TreeNode* tmp = root;   // 把root节点保存一下,下面来删除
                    root = root->right;     // 返回旧root的右孩子作为新root
                    delete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
                    return root;
                }
            }
            if (root->val > key) root->left = deleteNode(root->left, key);
            if (root->val < key) root->right = deleteNode(root->right, key);
            return root;
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    WPF中可冻结对象
    OpenCV-Python学习(13)—— OpenCV 多边形填充与绘制(cv.fillPoly、cv.polylines)
    【设计模式】一、设计模式七大原则
    翼龙面板是什么,如何进行搭建
    SpringSecurity授权流程(自己做笔记用的)
    Mysql安装
    CSP-J2022普及组题解T1:乘方
    正则表达式
    Java常见漏洞——整数溢出漏洞、硬编码密码漏洞、不安全的随机数生成器
    迈向100倍加速:全栈Transformer推理优化
  • 原文地址:https://blog.csdn.net/npu_yuanfang/article/details/138170713