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

打卡第22天,平衡二叉树,难,难,难。

今日任务

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

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

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

代码随想录算法训练营第二十二天 | 235. 二叉搜索树的最近公共祖先 、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点_第1张图片
在这里插入图片描述

我的题解

昨天的普通二叉树找最近公共祖先,直接搬过来了。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 递归出口
        if(root == NULL) return NULL;
        if(root == p || root == q) return root;

        TreeNode* leftNode = lowestCommonAncestor(root->left, p, q);  // 左
        TreeNode* rightNode = lowestCommonAncestor(root->right, p, q); //右

        // 中
        if(leftNode != NULL && rightNode != NULL) return root; //左右节点返回均不为空,说明root是p、q最近公共祖先
        if(leftNode != NULL && rightNode == NULL) return leftNode; //左节点不为空,说明左子树出现q或者q
        if(leftNode == NULL && rightNode != NULL) return rightNode; //右节点不为空,说明右子树出现q或者q
        return NULL; // 均为空,说明左右子树均不出现p、q
    }
};

代码随想录

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

递归法

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL) return NULL;
        
        // 当p、q结点的值都 小于 此时结点的值,说明最近的公共祖先结点在左子树
        if(root->val > p->val && root->val > q->val) {
            TreeNode* leftNode = lowestCommonAncestor(root->left, p, q);
            if(leftNode) return leftNode;
        } 
        // 当p、q结点的值都 大于 此时结点的值,说明最近的公共祖先结点在右子树
        if(root->val < p->val && root->val < q->val) {
            TreeNode* rightNode = lowestCommonAncestor(root->right, p, q);
            if(rightNode) return rightNode;
        }
         // 当p、q结点的值 不全都小于,也不全都大于 此时结点的值,说明p、q结点分别在此时结点的左右子树两侧,那么最近的公共祖先结点就是此时的结点
        return root;
    }
};

迭代法


class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root) {
        	// 当p、q结点的值都 小于 此时结点的值,说明最近的公共祖先结点在左子树
            if(root->val < p->val && root->val < q->val) root = root->right;
            // 当p、q结点的值都 大于 此时结点的值,说明最近的公共祖先结点在右子树
            else if(root->val > p->val && root->val > q->val) root = root->left;
            // 当p、q结点的值 不全都小于,也不全都大于 此时结点的值,说明p、q结点分别在此时结点的左右子树两侧,那么最近的公共祖先结点就是此时的结点
            else break;
        }
        return root;
    }
};

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

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

给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

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

代码随想录

按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了

迭代方法

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        TreeNode *node = new TreeNode(val);
   
        if(root == NULL) return node;

        TreeNode *cur = root;
        TreeNode* parent = root; //记录前一个结点

        while(cur != NULL) {
            parent = cur;
            if(val < cur->val) cur = cur->left;
            else cur = cur->right;
        }
		// 当遇到结点为空,插入我们的val结点
        if(val > parent->val) {
            parent->right = node;
        }
        else {
            parent->left = node;
        }
        
        return root;
    }
};

递归法

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

递归函数不用返回值也可以,找到插入的节点位置,直接让其父节点指向插入节点,结束递归,也是可以的。

 class Solution {
private:
    TreeNode* parent;
    void traversal(TreeNode* cur, int val) {
        if (cur == NULL) {
            TreeNode* node = new TreeNode(val);
            if (val > parent->val) parent->right = node;
            else parent->left = node;
            return;
        }
        parent = cur;
        if (cur->val > val) traversal(cur->left, val);
        if (cur->val < val) traversal(cur->right, val);
        return;
    }

public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        parent = new TreeNode(0);
        if (root == NULL) {
            root = new TreeNode(val);
        }
        traversal(root, val);
        return root;
    }
};

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

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

  • 首先找到需要删除的节点;
  • 如果找到了,删除它。

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

代码随想录

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        // 第一种情况:没找到删除的节点,遍历到空节点直接返回 NULL
        if(root == NULL) return NULL;
        if(root->val == key) {
            // 第二种情况:找到要删除的节点,而且他的左右节点都为空,直接返回 NULL
            if(root->left == NULL && root->right == NULL) {
                delete root; //释放内存
                return NULL;
            } 
            // 第三种情况:找到删除的节点,而且它的右节点为空,直接返回左孩子
            else if(root->left != NULL && root->right == NULL) {
                auto retNote = root->left;
                delete root; 
                return retNote;
            }
            // 第四种情况:找到删除的节点,而且它的左节点为空,直接返回右孩子 
            else if(root->left == NULL && root->right != NULL) {
                auto retNote = root->right;
                delete root; 
                return retNote;
            }
            // 第五种情况:找到删除的节点,但是它的左右节点为空
            // 找到该节点的右子树的最左节点,把该节点的左子树放在最左节点的左孩子
            // 返回该节点的右孩子
            else {
                TreeNode* cur = root->right;
                while(cur->left != NULL) cur = cur->left;
                cur->left = root->left;
                
                auto retNote = root; 
                root = root->right;  //返回旧root的右孩子作为新root
                delete retNote;  //释放内存
                return root;
            }
        }

        if(root->val > key) root->left = deleteNode(root->left, key); 
        if(root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

你可能感兴趣的:(算法,算法,leetcode,数据结构)