代码随想录第21天第三题+代码随想录第22天 | 236 二叉树的最近公共祖先 235 二叉搜索树的最近公共祖先 701二叉搜索树中的插入操作 450 删除二叉搜索树中的节点

236 二叉树的最近公共祖先

不会做,看了视频讲解思路后自己写出来了

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

        left = self.lowestCommonAncestor(root.left,p,q)
        right = self.lowestCommonAncestor(root.right,p,q)

        if left != None and right == None:
            return left
        if left == None and right != None:
            return right
        if left != None and right != None:
            return root
        if left == None and right == None:
            return None

非常巧妙地包含了pq分布在不同子树和相同子树上的两种情况,使用后续遍历,回溯记录是否访问到了p和q,当某节点回溯同时遇到pq时则说明其是最近公共祖先

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

使用上一题的思路,添加了根据root的val判断左右子树,结果无法通过了,为什么?
这思路有问题,不能根据root的val判断左右子树,这样会在找pq时遍历两遍树,看解答发现压根不需要判断,直接从上往下找第一个值在pq中间的即可

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

        return left or right

不过实际写出来的思路还跟解答的实现思路不太一样,解答是我一开始想到的思路的正确版本,要判断root同时大于pq或同时小于pq的情况,而不是分别比p和比q
不过解答的迭代法挺简洁的,值得学习

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

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

使用迭代和二叉搜索树的性质寻找插入位置,然后插入

class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        temp = root
        node = TreeNode()
        node.val = val
        if root == None:
            return node
        while temp:
            if temp.val > val:
                if temp.left != None:
                    temp = temp.left
                else:
                    temp.left = node
                    break
            elif temp.val < val:
                if temp.right != None:
                    temp = temp.right
                else:
                    temp.right = node
                    break
        return root

以后一定得注意检查输入节点为空的情况!
再用递归写一下试试
没成功,有个算例莫名其妙无法通过,看了下解答思路比我清晰许多

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

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

分析得知更新二叉搜索树应当是右边节点提上来,左边节点加到右子树的最左边
但要分几种情况讨论,若删除节点为叶子节点,则无需更新
若删除节点只有左子树或右子树,则直接提上来
若删除节点同时有左右子树,则需要更新
先用迭代写,逻辑太绕了,写得十分丑陋,简直是做得最丑陋的答案之一

class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        ## 首先找到删除节点
        if not root: return root
        temp = root
        pre = None
        while temp.val != key:
            if temp.val < key:
                pre = temp
                temp = temp.right
            elif temp.val > key:
                pre = temp
                temp = temp.left
            if temp == None:
                return root
        if not temp.left and not temp.right:
            if pre == None:
                return None
            if pre.left != None:
                if pre.left.val == key:
                    print(1)
                    pre.left = None
            if pre.right != None:
                if pre.right.val == key:
                    pre.right = None
        elif temp.left and temp.right:
            if pre == None:
                temp = temp.right
                while temp.left:
                    temp = temp.left
                temp.left = root.left
                return root.right
            if pre.left != None:
                if pre.left.val == key:
                    pre.left = temp.right
                    left = temp.left
                    temp = temp.right
                    while temp.left:
                        temp = temp.left
                    temp.left = left
            if pre.right != None:
                if pre.right.val == key:
                    pre.right = temp.right
                    left = temp.left
                    temp = temp.right
                    while temp.left:
                        temp = temp.left
                    temp.left = left
        elif temp.left == None and temp.right != None:
            if pre == None:
                return root.right
            if pre.left != None:
                if pre.left.val == key:
                    pre.left = temp.right
            if pre.right != None:
                if pre.right.val == key:
                    pre.right = temp.right
        else:
            if pre == None:
                return root.left
            if pre.left != None:
                if pre.left.val == key:
                    pre.left = temp.left
            if pre.right != None:
                if pre.right.val == key:
                    pre.right = temp.left
        return root

看一下解答,递归还算简洁,迭代法也比较繁琐
我对情况的分析是没错的,但是key所在节点在前一个节点的左边还是右边,以及key出现在根节点的情况写得太麻烦了

class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        if root is None:
            return root
        if root.val == key:
            if root.left is None and root.right is None:
                return None
            elif root.left is None:
                return root.right
            elif root.right is None:
                return root.left
            else:
                cur = root.right
                while cur.left is not None:
                    cur = cur.left
                cur.left = root.left
                return 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

实际上只是通过递归找到key所在节点,然后进行操作的。解答中另一种递归思路是找到后把key与右子树最左边节点交换,然后递归操作的

        if pre.left and pre.left.val == key:
            pre.left = self.deleteOneNode(cur)
        if pre.right and pre.right.val == key:
            pre.right = self.deleteOneNode(cur)
``
在递归中可以这样写来避免pre.left或pre.right报错,因为python会先判断第一个条件,如果为False就不再看第二个条件了(and情况下)
此外,python中is有时候很好用,它和==的区别在于,==判断两者内容是否相同,is则判断两者是不是同一个东西,如果内容相同但不是一个东西则is会返回False`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值