代码随想录Day_22打卡

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

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

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

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

事例:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和结点 8 的最近公共祖先为结点 6。

思路:

        普通二叉树的最近公共祖先需要自底向上查询,即后序遍历先收集左右子树结果最终返回。二叉搜索树可以利用中序遍历结点值有序的特点,不难得出祖先都在两结点中间,即祖先的结点值介于两节点之间。故可以使用从上到下即前序遍历方法获得最近公共祖先。

        Ps:当递归结点第一次介于两结点之间时,两结点一个位于左子树一个位于右子树,此时应当返回结果。此时若往左或往右走,都会错过其中一个结点。

代码:

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //递归
        //return traversal(root,p,q);

        //迭代
        TreeNode cur = root;
        while(cur != null){
            if(p.val < cur.val && q.val < cur.val) cur = cur.left;
            else if(p.val > cur.val && q.val > cur.val) cur = cur.right;
            else return cur;
        }
        return null;
    }

    public TreeNode traversal(TreeNode root,TreeNode p,TreeNode q){
        if(root == null) return root;
        if(p.val < root.val && q.val < root.val){
            TreeNode left = traversal(root.left,p,q);
            if(left != null) return left;
        }
        if(p.val > root.val && q.val > root.val){
            TreeNode right = traversal(root.right,p,q);
            if(right != null) return right;
        }

        return root;
    }

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

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

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

事例:

输入:root = [4,2,7,1,3], val = 5
输出:[4,2,7,1,3,5]

思路:

        插入途中要保存二叉搜索树的性质不变,即中序遍历结点值是有序的。故可以根据目标值判断当前结点向左或向右走。即遍历树,使用全局变量pre记录前一个结点,当遍历到空节点时,pre插入目标值的结点即可。

代码:

public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null) return new TreeNode(val);
        // 递归
        // insertNode(root,val);
        // return root;

        //迭代
        TreeNode cur = root;
        TreeNode pre = null;
        while(cur != null){
            pre = cur;
            if(cur.val < val){
                cur = cur.right;
            }else {
                cur = cur.left;
            }
        }
        TreeNode tmp = new TreeNode(val);
        if(pre.val < val) pre.right = tmp;
        if(pre.val > val) pre.left = tmp;

        return root;
    }

    private TreeNode pre = null;
    public void insertNode(TreeNode root,int val){
        if(root == null){
            TreeNode tmp = new TreeNode(val);
            if(pre.val < val) pre.right = tmp;
            else pre.left = tmp;
            return;
        }
        pre = root;
        if(root.val < val){
            //往右边寻找
            insertNode(root.right,val);
        }else{
            //往左边寻找
            insertNode(root.left,val);
        }
    }

③、删除二叉搜索树中的结点

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

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

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

事例:

输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]

思路:

        跟上题一样,利用二叉搜索树的特性,当前值比目标值大时往左走,比目标值小时往右走,当两值相等时,进行删除操作。可以利用递归返回值结果(当往左走时,返回的是删除操作完后的左子树),故root.left = delete(root.left,key) root.right = delete(root.right,key),最后返回完整的树即为最终结果。

        具体删除操作:

当目标结点为叶子结点时,返回null

当目标结点只有左子树或右子树时,返回不为null的子树

当目标结点既有左子树又有右子树时,在右子树中找到最小值(即右子树中的最左结点),将最小值赋给目标结点,此时,右子树中的最左结点就重复了,变成了删除右子树中的最左结点,root.right = delete(root.right,root.val)。

代码:

 public TreeNode deleteNode(TreeNode root, int key) {
        root = delete(root,key);
        return root;
    }


    public TreeNode delete(TreeNode root,int key){
        if(root == null) return null;
        if(key < root.val){
            //往左边寻找删除
            root.left = delete(root.left,key);
        }else if(key > root.val){
            //往右边寻找删除
            root.right = delete(root.right,key);
        }else{
            //删除目标结点
            if(root.left == null) return root.right;
            else if(root.right == null) return root.left;
            else{
                //目标结点既有左子树又有右子树
                TreeNode tmp = root.right;
                //寻找右子树中的最小值
                while(tmp.left != null){
                    tmp = tmp.left;
                }
                //交换比标值和右子树中的最小值
                root.val = tmp.val;
                //删除赋值过来的结点
                root.right = delete(root.right,tmp.val);
            }
        }
        
        return root;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值