代码随想录day22:二叉树07(二叉搜索树公共祖先,二叉搜索树插入,删除二叉搜索树节点)

1. 二叉搜索树最近公共祖先(leetcode 235)

迭代法

这题与寻找二叉树的最近公共祖先不一样,我们可以利用二叉搜索树的特性,看当前节点与pq的值的大小关系,然后不停往正确的道路迭代,最终就能找到公共祖先

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            if p.val > root.val and q.val > root.val:
                root = root.right
            elif p.val < root.val and q.val < root.val:
                root = root.left
            elif p.val > root.val and q.val < root.val:
                return root
            elif p.val < root.val and q.val > root.val:
                return root
            elif p.val == root.val:
                return p
            elif q.val == root.val:
                return q

处理好每种情况就行了

递归法:

本题是二叉搜索树,二叉搜索树是有序的,那得好好利用一下这个特点。

在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?

因为是有序树,所以 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。

那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是p 和 q的公共祖先。 那问题来了,一定是最近公共祖先吗

如图,我们从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点5,此时可以说明 q 和 p 一定分别存在于 节点 5的左子树,和右子树中。

递归三部曲:

1. 确认递归值和参数:参数为当前节点,p,q。返回值为最近公共祖先

2. 终止条件:遇到空节点返回

3. 确定单层递归逻辑:比大小顺着路走。走完了以后直接return root。

完整代码:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root.val > p.val and root.val > q.val:
            left = self.lowestCommonAncestor(root.left, p, q)
            if left is not None:
                return left
        
        if root.val < p.val and root.val < q.val:
            right = self.lowestCommonAncestor(root.right, p, q)
            if right is not None:
                return right
        
        return root

2. 二叉搜索树中的插入(leetcode 701)

我们可以用迭代法,对比val和root的大小,遍历到最接近val的叶子,然后在结尾加上他

class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return TreeNode(val)
        current = root
        parent = root
        while current:
            if val > current.val:
                parent = current
                current = current.right
            elif val < current.val:
                parent = current
                current = current.left

        if val > parent.val:
            parent.right = TreeNode(val)
        elif val < parent.val:
            parent.left = TreeNode(val)
        return root

但因为你需要两个指针来记录中间遍历的母子,所以还是比较花时间的

递归法也是一样的道理

class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return TreeNode(val)
        if root.val > val:
            root.left = self.insertIntoBST(root.left, val)
        elif root.val <val:
            root.right = self.insertIntoBST(root.right, val)
        return root

3. 删除二叉搜索树中的节点(leetcode 450)

我们在删除节点主要有两个步骤

首先我们要找到目标节点,找到了再删除。

首先我们先通过递归函数来寻找节点,然后再讨论删除的具体操作

递归三部曲:首先先确认我们用前序遍历。

1. 确定参数以及返回值:参数就是当前节点

2. 终止条件:如果遇到空节点也没找到删除的节点,直接返回root

3. 确定单层递归逻辑

如果没找到target,遍历到空节点我们就返回了

当我们遇到要删除的节点时,一共有一下几种情况

- 第一种,左右孩子都为空,直接删除,返回NULL

-第二种,左孩子为空,右孩子不为空,直接返回右孩子

-第三种,右孩子为空,左孩子不为空,返回左孩子

-第四种,左右孩子都不为空:我们可以将删除节点的左孩子整颗子树放到右孩子最左边的叶节点的左边,并返回右孩子成为新的节点。

具体步骤如图。(图源代码随想录)

这道题的关键就在于当左右孩子都存在的情况下,我们要怎么删除节点。要注意运用二叉搜索树的性质。

class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        if root is None:
            return root
        if root.val == key:
            if not root.left and not root.right:
                return None
            elif not root.left and root.right:
                return root.right
            elif not root.right and root.left:
                return root.left
            elif root.left and root.right:
                cur = root.right
                while cur.left is not None:
                    cur = cur.left
                cur.left = root.left
                return root.right
        #这里相当于把新的节点返回给上一层,上一层就要用 root->left 或者 root->right接住
        if root.val > key:
            root.left =  self.deleteNode(root.left, key)
        if root.val < key:
            root.right = self.deleteNode(root.right, key)
        
        return root

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值