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

48 阅读3分钟

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

题目链接

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

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路

二叉搜索树不纠结于搜索顺序,可以直接从上往下遍历,只要节点的值在[p, q]之间,那么他一定是最近公共祖先 1.递归法

var lowestCommonAncestor = function(root, p, q) {
    if(root == null) return root
    if(root.val > p.val && root.val > q.val){
        let left = lowestCommonAncestor(root.left, p, q)
        if(left != null) return left
    }else if(root.val < p.val && root.val < q.val){
        let right = lowestCommonAncestor(root.right, p, q)
        if(right != null) return right
    }else {
        return root
    }
};

//简化
var lowestCommonAncestor = function(root, p, q) {
    if(root.val > p.val && root.val > q.val){
       return lowestCommonAncestor(root.left, p, q)
    }else if(root.val < p.val && root.val < q.val){
        return lowestCommonAncestor(root.right, p, q)
    }else {
        return root
    }
};

2.迭代法

    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. 二叉搜索树中的插入操作

题目链接

要求:给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

思路

添加节点不用改变树的结构,本题通过递归函数返回值完成新加入节点的父子关系赋值操作,下一层将加入节点返回,本层用root->left或者root->right将其接住。

var insertIntoBST = function(root, val) {
    if(root == null) {
        //找到叶子节点 即插入节点的位置了
        const node = new TreeNode(val)
        return node
    }
    if(root.val > val){
        root.left = insertIntoBST(root.left, val)
    }else if(root.val < val){
        root.right = insertIntoBST(root.right, val)
    }
    return root
};

在迭代法遍历的过程中,需要记录一下当前遍历的节点的父节点,这样才能做插入节点的操作。

var insertIntoBST = function(root, val) {
    if(root == null){
        let node = new TreeNode(val)
        return node
    }
    let cur = root, parent = root
    while(cur != null){
        parent = cur
        if(cur.val > val){
            cur = cur.left
        }else cur = cur.right
    }
    let node = new TreeNode(val)
    if(val<parent.val) parent.left = node
    else parent.right = node 

    return root
    
};

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

题目链接

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

一般来说,删除节点可分为两个步骤:

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

思路

本题比较复杂,因为需要改变树的结构;

难点主要是分析二叉搜索树中删除节点遇到的情况:

  • 第一种情况:没找到删除的节点,那么遍历到空节点直接返回;
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(即叶子节点),直接删除节点,返回null
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:删除节点的左、右孩子都不为空,应该将删除节点的左子树放到删除节点的右子树最左侧的节点下面
var deleteNode = function(root, 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 {
            let cur = root.right //指向删除节点的右子树
            while(cur.left != null) cur=cur.left //这样才能找到右子树下面最小的数
            cur.left = root.left
            return root.right
        }
    }
    if(key < root.val) root.left = deleteNode(root.left, key)
    if(key > root.val) root.right = deleteNode(root.right, key)
    return root
};