Day 17 打卡 二叉树part05

二叉树的题真是一节更比六节强,先补上昨天的最后一题

LC 106. 从中序与后序遍历序列构造二叉树

拿到这题,当然是一脸懵,甚至不知道根节点在哪?

不过考虑到后序遍历的特性:左右中,postorder数组的最后一个元素,一定是根节点。再到inorder数组中去找对应的左右子树范围(postorder中找每棵树的根节点,以此把前序数组分割成左右两个部分,代表两棵子树),再递归的去切分左右子树,便能构造完整的树。(草稿纸上用手模拟一遍,过程还是很清晰,但是代码不知道咋写)

具体来说,分为以下六步:

  • 第一步:如果数组大小为零的话,说明是空节点了。 递归出口

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

    class Solution:
        def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
    #递归出口,当postorder的长度为零,说明构造完了
            if len(postorder) == 0:
                return None
    #以下是单层处理逻辑,首先找到每颗子树的根节点
            node = TreeNode(postorder[-1])
            inorder_index = inorder.index(node.val)
    #用后序数组的根节点,到中序数组中找到左右子树对应的范围
            inorder_left = inorder[:inorder_index]
            inorder_right = inorder[inorder_index + 1 :]
    '''中序数组中,左右子树范围对应的长度,应该等于后续数组中左右子树范围对应的长度
    以此找到,后续数组中。左右子树所在的区间,再取后续数组的最后一个元素,又找到对应子树
    的根节点,此即递归逻辑
    '''
            postorder_left = postorder[:len(inorder_left)]
            postorder_right = postorder[len(inorder_left) : len(inorder_left) + len(inorder_right)]
    #递归调用,构建二叉树
            node.left = self.buildTree(inorder_left , postorder_left )
            node.right = self.buildTree(inorder_right , postorder_right)
    
            return node

    LC 654. 最大二叉树                                                                                                                     终于自己写出来一次 ,可喜可贺!

  • class Solution:
        def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
            if not nums:
                return 
            M = max(nums)
            root = TreeNode(M)
            idx = nums.index(M)
            nums_left = nums[:idx]
            nums_right = nums[idx + 1 :]
    
            if len(nums_left) == 0 and len(nums_right) == 0:
                return root
    
            if len(nums_left) == 0:
                root.left = None
            root.left = self.constructMaximumBinaryTree(nums_left)
    
            if len(nums_right) == 0:
                root.right == None
            root.right = self.constructMaximumBinaryTree(nums_right)
    
            return root

    其实做的过程中,没思考用哪种遍历方式,很自然的使用了先序。因为只有先设置根节点,才能再设置左右节点的指针。 

  • 实际操作中,我是一上来就把数组从最大值切分成左右两个子数组,递归出口自然就是左右两边都为空,比如[1]这种情况(卡哥的方法是直接检测数组长度,若为1则到达递归出口,本质是一样的)。由于是先切分,有可能导致后续

    root.right = self.constructMaximumBinaryTree(nums_right)

    这种语句中传入空列表,因此需要在开头加上判断语句,遇到空列表直接返回。

  • 事实上不加判断也可以,在后面递归调用的时候加上if-else语句,避免在空列表的情况下调用函数即可,如下:

  •         if len(nums_right) == 0:
                root.right == None
            else:
                root.right = self.constructMaximumBinaryTree(nums_right)

    这和之前的区别是,之前即便是空列表,设置为了None之后,还会调用函数一次,现在空列表就不会调用了。

  • 700. 二叉搜索树中的搜索

  • 代码容易,但是要注意和前几题的区别:本题递归函数调用时有返回值!

  • 为什么会有返回值?因为当检测到节点值和target相等时,我们就要把这个节点返回出来,若不用res接住返回值,func函数将无值可返(一开始想当然的写成在func最后return node,也没用res,输出的自然是整棵树)。而前面几题调用时没有返回值是因为后面还要对其进行某种操作,在最后在输出操作完成后的结果,本题是满足条件,立即输出,因此必须要当场返回

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值