LeetCode 打卡day22 -二叉搜索树的最小公共祖先,BST节点的插入和删除


知识总结

今天是二叉搜索树专题, 尤其是二叉搜索树的插入和删除, 需要掌握


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

题目链接

题目说明

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

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

代码说明

方法一: 按照一般二叉树的方法

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return dfs(root, p, q);
    }

    public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if (root == null) return null;
        if (root == p || root == q) return root;

        TreeNode left = dfs(root.left, p, q);
        TreeNode right = dfs(root.right, p, q);
        if(left != null && right != null) return root;
        if(left == null && right != null) return right;
        if(left != null && right == null) return left;
        return null;
    }
}

方法二, 利用二叉搜索树的特性, 一边大一边小说明需要该root为最小的公共祖先, 所以我们使用异或的操作

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return dfs(root, p, q);
    }

    public TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if (root == null || root.val == p.val || root.val == q.val) return root;
        if((root.val - p.val > 0) ^ (root.val - q.val > 0)) return root;
        if((root.val - p.val) > 0 && (root.val - q.val) > 0) {
            return dfs(root.left, p, q);
        }else{
            return dfs(root.right, p, q);
        }
    }
}

方法三, 迭代法, 比较好理解,从上往下依次遍历

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        TreeNode ancestor = root;
        while(true){
            if(ancestor.val > p.val && ancestor.val > q.val){
                ancestor = ancestor.left;
            }else if(ancestor.val < p.val && ancestor.val < q.val){
                ancestor = ancestor.right;
            }else{
                break;
            }
        }
        return ancestor;
    }
}

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

题目链接

题目说明

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

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

代码说明

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null) return new TreeNode(val);
        dfs(root, val);
        return root;
    }

    public void dfs(TreeNode root, int val){
        if(root.val > val){
            if(root.left == null){
                root.left = new TreeNode(val);
            }else{
                dfs(root.left, val);
            }
        }else{
            if(root.right == null){
                root.right = new TreeNode(val);
            }else{
                dfs(root.right, val);
            }
        }
    }
}

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

题目链接

题目说明

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

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

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

代码说明

方法一: 递归法, 分类讨论, 当需要被删除的节点两边都要子树时, 需要找一个继承者successor(右子树的最小节点)来取代删除的节点。
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( N ) O(N) O(N)

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root == null) return root;
        if(root.val > key) {
            root.left = deleteNode(root.left, key);
            return root;
        }
        if(root.val < key) {
            root.right = deleteNode(root.right, key);
            return root;
        }
        // 相等
        // 叶子节点
        if(root.left == null && root.right == null){
            return null;
        }else if(root.left == null && root.right != null){
            return root.right;
        }else if(root.left != null && root.right == null){
            return root.left;
        }else{
            // 两边都有, 找到继承者
            TreeNode successor = root.right;
            while(successor.left != null){
                successor = successor.left;
            }
            root = deleteNode(root, successor.val);
            successor.left = root.left;
            successor.right = root.right;
            return successor;
        }
    }

方法二: 不去递归, 储存一个额外的父节点来迭代, 代码相对复杂不少。
时间复杂度 O ( N ) O(N) O(N)
空间复杂度 O ( 1 ) O(1) O(1)


class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        TreeNode cur = root, curParent = null;
        while(cur != null && cur.val != key){
            curParent = cur;
            cur = cur.val > key ? cur.left : cur.right;
        }

        if(cur == null) return root;
        if(cur.left == null && cur.right == null){
            cur = null;
        }else if(cur.right == null){
            cur = cur.left;
        }else if(cur.left == null){
            cur = cur.right;
        }else{
            TreeNode successor = cur.right, succPar = cur;
            while(successor.left != null){
                succPar = successor;
                successor = successor.left;
            }

            // 删除successors
            if(succPar.val == cur.val){
                succPar.right = successor.right;
            }else{
                succPar.left = successor.right;
            }
			// successor 取代原节点
            successor.right = cur.right;
            successor.left = cur.left;
            cur = successor;
        }

        if(curParent == null){
           return cur;
        }else{
                if(curParent.left != null && curParent.left.val == key){
                    curParent.left = cur;
                }else{
                    curParent.right = cur;
                }
                return root;
            }
       }    
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值