二叉树习题5:二叉搜索树的最近公共祖先、二叉搜索树中的插入操作、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、把二叉搜索树转换成累加树

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

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

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

示例

除了可以利用普通二叉树的最近公共祖先的代码,要知道二叉搜索树是有特性的,那就是左右子树分别小于大于根节点。
因此,在二叉搜索树中,如果一个节点处于P和q的取值区间内,那么该节点就有可能是公共祖先,这就是最近的祖先吗?
如下图所示,从上至下的递归中第一个找到的公共祖先是5,如果往左走就错过了p的祖先,如果往右走就错过了q的祖先,因此第一次找到取值范围内的节点就是最近的公共祖先。
例子

class Solution{
    public TreeNode lowsetCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root==null || root==p || root==q) return root;
        //中
        if(root.val>q.val && root.val>p.val){
            TreeNode left=lowsetCommonAncestor(root.left,p,q);
            if(left!=null)
                return left;
        }
       if(root.val<q.val && root.val<p.val){
            TreeNode right=lowsetCommonAncestor(root.right,p,q);
            if(right!=null)
                return right;
        }
       return root;
    }
}

/*迭代法
public TreeNode lowsetCommonAncestor(TreeNode root,TreeNode q,TreeNode q)
{
while(root){
if(root.val>q.val && root.val>p.val) root=root.left;
else if(root.val<q.val && root.val<p.val) root=root.right;
else break;
}
return root;
}

二叉搜索树中的插入操作

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

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

示例
中序遍历,如果碰到根节点小于val,就往右走,如果根节点小于val,就往左走,当往下走碰到空时插入

class Solution {
    int flag=1;
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root==null && flag==1){
             TreeNode res=new TreeNode(val);
             return res;
        }
        else if(root==null && flag!=1) return root;
if(root.val>val){
    flag=0;
    TreeNode left=insertIntoBST(root.left,val);
    if(root.left==null){
        root.left=new TreeNode(val);
    }
}
else if(root.val<val){
    flag=0;
    TreeNode right=insertIntoBST(root.right,val);
    if(root.right==null){
        root.right=new TreeNode(val);
    }
}
return root;
    }
    }

删除二叉搜索树中的节点

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

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

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

示例

递归遍历二叉树,难点是找到要删除的节点后,不能直接删除,而是要判断节点的位置,存在以下几种情况:
1.要删除的节点是叶子节点则直接删除;
2.要删除的节点左孩子为空,右孩子不为空,删除节点,右孩子补位。
3.要删除的节点左孩子不为空,右孩子为空,删除节点,左孩子补位。
4.左右孩子都不为空,则将删除节点的左孩子放到删除节点右子树最左边节点下。

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return root;
    if(root.val==key){//中
    if(root.left==null && root.right==null){
        return null;
    }
   else if(root.left==null && root.right!=null){
        root=root.right;
    }
    else if(root.left!=null && root.right==null){
        root=root.left;
    }
    else{//删除节点的左右子树都不为空:把删除节点的左子树放到删除节点右子树的最左边节点的左子树
        TreeNode cur=root.right;
        while(cur.left!=null){
            cur=cur.left;
        }
    cur.left=root.left;
    //删除root
    root=root.right;
    return root;
    }
    }
    if(root.val>key){//左
        root.left=deleteNode(root.left,key);
    }
    if(root.val<key){//右
        root.right=deleteNode(root.right,key);
    }
    return root;
    }
    }

修剪二叉搜索树

例题669:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

示例

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if(root==null) return null;
        if(root.val<low){
            return trimBST(root.right,low,high);
        } 
        if(root.val>high){
            return trimBST(root.left,low,high);
        }       
        root.left=trimBST(root.left,low,high);
        root.right=trimBST(root.right,low,high);
      return root;
    }
}

与上一题删除一个节点不同,该题需要把握住二叉搜索树的特性,如果删除节点值小于low,则说明其左子树也需要删除,如果删除节点值大于high,则说明右子树也全都大于high需要删除。

将有序数组转换为二叉搜索树

例题108:给你一个整数数组 nums ,其中元素已经按
升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
在这里插入图片描述

在这里插入图片描述

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
       return traversal(nums,0,nums.length);//左闭右开区间
    }

    public TreeNode traversal(int[] nums,int left,int right){
    if(left>=right) return null;
    int pos=left+(right-left)/2;//(left+right)/2可能会溢出
    TreeNode root=new TreeNode(nums[pos]);//数组可以[pos]直接取值,如果是List则需要用get(pos)
    root.left=traversal(nums,left,pos);
    root.right=traversal(nums,pos+1,right);
    return root;
    }
}

类似于构造二叉树,主要是遍历的过程找到根节点,以及根据根节点划分左右区间

把二叉搜索树转换成累加树

例题538:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。

示例

根据右中左的顺序遍历二叉树,定义一个变量记录前一个节点的值,这样每次遍历节点时就加上前一个节点值。

class Solution {
    int pre=0;
    public TreeNode convertBST(TreeNode root) {
//按照右中左的遍历顺序累加
if(root==null) return root;
root.right=convertBST(root.right);
root.val+=pre;
pre=root.val;
root.left=convertBST(root.left);
return root;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值