leetcode分类刷题:二叉树(九、二叉搜索树的节点插入删除)

二叉搜索树的节点插入删除通过返回不同情况下的对应节点来覆盖进行实现

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

题眼:二叉搜索树中的插入——一定能够找到孩子节点进行插入(这一点很难想到并且想通),通过返回节点覆盖来实现插入
思路1、递归遍历:重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择插入左右子树——这个题反倒是递归法更容易想出来
思路2、迭代遍历:二叉搜索树值的查找(特有的迭代遍历)+二叉搜索树的最小绝对值(双指针需要前指针保存父节点) 结合

'''
701. 二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点root和要插入树中的值value,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 
输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
示例 1:
    输入:root = [4,2,7,1,3], val = 5
    输出:[4,2,7,1,3,5]
题眼:二叉搜索树中的插入——一定能够找到孩子节点进行插入(这一点很难想到并且想通),通过返回节点覆盖来实现插入
思路1、递归遍历:重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择插入左右子树——这个题反倒是递归法更容易想出来
思路2、迭代遍历:二叉搜索树值的查找(特有的迭代遍历)+二叉搜索树的最小绝对值(双指针需要前指针保存父节点) 结合
'''
class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        # 简单情况
        if root == None:
            return TreeNode(val)
        else:  # 重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择插入左右子树
            if root.val > val:
                root.left = self.insertIntoBST(root.left, val)
            elif root.val < val:
                root.right = self.insertIntoBST(root.right, val)
            return root

    # 二叉搜索树值的查找(特有的迭代遍历)+二叉搜索树的最小绝对值(双指针需要前指针保存父节点) 结合
    def insertIntoBSTIteratioin(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return TreeNode(val)
        parent = None
        cur = root
        while cur:  # 二叉搜索树特性的遍历方式:找到满足条件的叶子节点
            parent = cur
            if cur.val > val:
                cur = cur.left
            elif cur.val < val:
                cur = cur.right
        # 此时当前节点一定为None,parent保存了父节点
        if parent.val > val:
            parent.left = TreeNode(val)
        elif parent.val < val:
            parent.right = TreeNode(val)
        return root

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

题眼:删除二叉搜索树中的节点,可以参考“701. 二叉搜索树中的插入操作”通过返回节点覆盖来实现删除
思路:简单情况:没找到删除节点,返回None; 重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择左右子树继续找删除节点:找到删除节点:叶子节点,直接删除,即返回None;左子树为空,右子树不为空,返回右子树;左子树不为空,右子树为空,返回左子树;左、右子树都不为空,将左子树放到右子树最左面节点的左孩子上,返回右子树

'''
450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:首先找到需要删除的节点;如果找到了,删除它。
示例 1:
    输入:root = [5,3,6,2,4,null,7], key = 3
    输出:[5,4,6,2,null,null,7]
    解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
    一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
    另一个正确答案是 [5,2,6,null,4,null,7]。
题眼:删除二叉搜索树中的节点,可以参考“701. 二叉搜索树中的插入操作”通过返回节点覆盖来实现删除
思路:简单情况:没找到删除节点,返回None;
重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择左右子树继续找删除节点:找到删除节点:叶子节点,直接删除,即返回None;左子树为空,右子树不为空,返回右子树;
左子树不为空,右子树为空,返回左子树;左、右子树都不为空,将左子树放到右子树最左面节点的左孩子上,返回右子树
'''
class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        # 简单情况
        if root == None:                                    # 没找到删除节点,遍历到空节点直接返回
            return None
        # 重复逻辑:对每个二叉树根节点值判断、根据值大小关系选择左右子树继续找删除节点
        elif root.val == key:  # 找到了删除节点
            if root.left == None and root.right == None:    # 左右孩子都为空:叶子节点
                return None
            elif root.left == None and root.right != None:  # 左孩子空右孩子不为空
                return root.right
            elif root.left != None and root.right == None:  # 左孩子不为空右孩子空
                return root.left
            else:                                           # 左右孩子都不为空:把删除节点的左子树加到 右子树的左孩子上即可
                cur = root.right  # 指向删除节点的右子树
                while cur.left != None:  # 找到该节点的右子树的最左边的叶子
                    cur = cur.left
                cur.left = root.left  # 把删除节点的左子树放在 找到的 找到该节点的右子树的最左边的叶子
                return root.right
        elif root.val > key:
            root.left = self.deleteNode(root.left, key)
            return root
        elif root.val < key:
            root.right = self.deleteNode(root.right, key)
            return root

669. 修剪二叉搜索树

题眼:“450. 删除二叉搜索树中的节点” 的难度进阶版,可能会删除多个节点,同样是采用返回节点覆盖来实现删除
思路:递归-重复逻辑:对节点不断进行大小比较,进行修剪操作

'''
669. 修剪二叉搜索树
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。
修剪树 不应该改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
示例 1:
    输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3
    输出:[3,2,null,1]
题眼:“450. 删除二叉搜索树中的节点” 的难度进阶版,可能会删除多个节点,同样是采用返回节点覆盖来实现删除
思路:递归-重复逻辑:对节点不断进行大小比较,进行修剪操作
'''
class Solution:
    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
        # 简单情况
        if root == None:
            return None
        # 重复逻辑:对节点不断进行大小比较,进行修剪操作
        elif root.val < low:  # 删除该节点以及左子树,保留并修剪右子树
            return self.trimBST(root.right, low, high)
        elif root.val > high:  # 删除该节点以及右子树,保留并修剪左子树
            return self.trimBST(root.left, low, high)
        else:
            root.left = self.trimBST(root.left, low, high)
            root.right = self.trimBST(root.right, low, high)
            return root
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

22世纪冲刺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值