Leetcoder Day19| 二叉树 part08

语言:Java/Go

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

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

本题是昨天236二叉树最近公共祖先的特定版,单纯求二叉树的时候采用自底向上的回溯法,采用后序遍历。本题指定为二叉搜索树,所以第一时间想到中序遍历是有序的。那么p和q的公共祖先按照特性,值位于p和q中间。因此如果要找到最近的公共祖先,如下面的图所示,节点5位于p和q之间,如果继续向左或向右遍历,则错过了成为p或者q的祖先,因此5就是q和p的最近公共祖先。所以按照从上往下的顺序遍历,第一次遇到数值在p和q之间的,就是最近公共祖先。找到结果就直接返回。

class Solution {
    TreeNode traversal(TreeNode node, TreeNode p, TreeNode q){
        if(node==null || node.val==p.val||node.val==q.val){
            return node;
        }
        // 让a等于小的值,b等于大的值
        int a=p.val, b=q.val;
        int c;
        if(a>b){
            c=a;
            a=b;
            b=c;
        }
        if(node.val>=a && node.val<=b) return node;
        //向左
        if(node.val>b){
            TreeNode left=traversal(node.left, p,q);
            if (left!=null) return left;
        }
        //向右
        if(node.val<a){
            TreeNode right=traversal(node.right,p,q);
            if (right!=null) return right;
        }
        
        return null;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return traversal(root, p, q);
    }
}

GO:

func traversal(root, p, q *TreeNode)*TreeNode{
    //相当于java里的nul
	if root==nil || root.Val==p.Val || root.Val==q.Val {
        return root
    }
    var a,b int=p.Val,q.Val
    var c int
    if a>b{
        c=a
        a=b
        b=c
    }
    if root.Val>a && root.Val<b{
        return root
    }
    if(root.Val>b){
        var left=traversal(root.Left,p,q)
        if left!=nil{
            return left
        }
    }
    if(root.Val<a){
        var right=traversal(root.Right,p,q)
        if right!=nil{
            return right
        }
    }
    return nil

}

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    return traversal(root,p,q)
}

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

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

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

本题较简单的一个思路就是,判断待插入的值和根节点的关系,,然后将待插入的元素始终作为叶子节点插入即可。同样注意本题为二叉搜索树,所以不需要遍历整棵树。

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func traversal(root *TreeNode, val int) *TreeNode {
    if root==nil {
        root=&TreeNode{Val:val}    // 创建一个值为val的新节点
        return root
    }
    if root.Val>val{
        root.Left=traversal(root.Left,val)
        return root
    } 
    if root.Val<val{
        root.Right=traversal(root.Right,val)
        return root
    }
    return nil
}
func insertIntoBST(root *TreeNode, val int) *TreeNode {
    return traversal(root, val)
}

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

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

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

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

本题依然是二叉搜索树,所以要利用好有序的性质进行删除节点的查找,但是找到以后如何进行删除需要仔细。

  1. 若删除的是叶子节点,则直接删除,返回空为根节点;
  2. 若删除的是非叶子节点,则还需要将其左右孩子的位置进行重构:
    1. 如果左孩子为空,右孩子不为空,则需要用右孩子补位,返回右孩子为根节点;
    2. 如果右孩子为空,左孩子不为空,则需要用左孩子补位,返回左孩子;
    3. 若左右都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。

class Solution {
    TreeNode traversal(TreeNode root, int key){
        if(root==null) return root;
        if(root.val>key){
            root.left=traversal(root.left,key);
            return root;
            }
        if(root.val<key){
            root.right=traversal(root.right,key);
            return root;
            }
        //找到值等于key的节点
        if(root.val ==key){
            //没有左孩子
            if(root.left==null) return root.right;
            //没有右孩子
            else if(root.right==null) return root.left;
            //左右孩子均存在
            TreeNode cur=root.right;
            while(cur.left!=null){
                cur=cur.left;
            }
            cur.left=root.left;
            root=root.right;
            return root;

        }
        return null;
    }
    public TreeNode deleteNode(TreeNode root, int key) {
        return traversal(root, key);
    }
}

今日心得

这两天完成了对二叉搜索树的增删还有搜索的操作,一定要记住二叉搜索树的特点,不需要遍历整棵二叉树。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值