【二叉树】前序中序数组、中序后序数组创建二叉树、最大二叉树、将有序数组转换为二叉搜索树(BST)

目录

1.最大二叉树

1.1题目描述

1.2 思路

2.从前序与中序遍历序列构造二叉树

2.1题目描述

 2.2 思路

3.从中序与后序序列构造二叉树

3.1 题目描述

3.2思路


#刷题记录#

今天来分享三道关于二叉树的算法题

对应力扣:

1.最大二叉树

654. 最大二叉树 - 力扣(LeetCode)

2.从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

3.从中序与后序序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

这三道题的共性都是通过列表创建二叉树,需要涉及到对数组切分然后根据子数组创建二叉树的操作。

我们一起来看:

1.最大二叉树

1.1题目描述

 

1.2 思路

既然要求我们每次找出最大值,然后左右子列表的最大值,我们很自然的想到递归来解决,每次找出当前列表最大值,按照最大值索引,切分左右列表,再次进行操作。

      (1)确定输入和输出:

        输入的是nums数组,输出自然是根节点root

        (2) 确定递归终止条件/也可以理解为特殊情况处理:

    if not nums:
        return None

       (3)确定中间过程 

        首先我们需要找出最大值的下标索引并创建根节点

        然后根据最大索引对列表进行切分即可,左列表到最大值索引的左边一个索引,切片操作右边的索引不包含,所以我们可以写nums[:max_index],右列表的左边到最大值索引的右边一个索引,切片操作冒号左边会包含当前索引,所以我们写成nums[max_index+1:]

    # 最大值的下标
    max_index = nums.index(max(nums))
    
    # 创建根节点
    root = TreeNode(val = nums[max_index])
    
    # 根据最大值索引对列表进行切分
    left_nums = nums[:max_index]
    right_nums = nums[max_index+1:]

        之后分别求得左右节点

    root.left = self.constructMaximumBinaryTree(left_nums)
    root.right = self.constructMaximumBinaryTree(right_nums)

        (4)汇总

class Solution(object):
    def constructMaximumBinaryTree(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        # 处理特殊情况/二叉树的终止条件
        if not nums:
            return None

        # 确定最大值所在下标
        max_index = nums.index(max(nums))

        # 创建根节点
        root = TreeNode(val = nums[max_index])

        # 对数组进行切分
        left_nums = nums[:max_index]
        right_nums = nums[max_index+1:]

        # 左右节点
        root.left = self.constructMaximumBinaryTree(left_nums)
        root.right = self.constructMaximumBinaryTree(right_nums)

        return root

可能会有同学有疑问,如果切片操作中的max_index+1超出索引范围,不会报错(out of range)吗?

事实上并不会,当使用 list[start:end] 这样的切片操作时,如果 startend 超出了列表的索引范围,Python 不会报错,而是会返回一个适当的列表。如果 start 大于列表的最大索引,你会得到一个空列表。同样,如果 end 大于列表的最大索引,切片操作会返回从 start 到列表末尾的所有元素。

2.从前序与中序遍历序列构造二叉树

2.1题目描述

 2.2 思路

        根据前序和中序的遍历顺序“中左右”我们可以得知,前序遍历序列中的第一个元素就是当前序列的根节点。我们就可以通过中序序列确定根节点所在,从而我们可以通过中序序列“左中右”的特点,根据从前序序列获得的中节点,将中序序列切分为左右两个部分。

        而后,我们再根据从中序序列获取的左右子序列的长度,可以对前序序列的左右进行划分。在利用递归,求的左右子树。

     (1)确定输入和输出:

        容易知道,我们的输入是前序序列preorder和中序序列inorder,输出是root根节点

      (2)确定递归终止条件:

        当前序序列或中序序列为空时返回None

    if not preorder:
        return None

        (3)确定中间过程

        首先我们创建根节点,根据前序序列的第一个元素,并找到中序序列中根节点所在位置便于切分:

    # 创建根节点,先序数组中的第一个是根节点
    root = TreeNode(preorder[0])
    # 确定切分中序数组的下标
    split_index = inorder.index(root.val)

        而后我们根据获得的split_index,对中序数组进行左右切分,在获中序左右序列之后,我们就可以根据其长度切分前序序列:

    # 确定左和右的中序数组
    left_inorder = inorder[:split_index]
    right_inorder = inorder[split_index+1:]

    # 根据前序和中序数组的左右长度必然相同,对前序数组进行切分
    left_preorder = preorder[1:len(left_inorder)+1]
    right_preorder = preorder[len(left_inorder)+1:]

        最后我们确定左右子树即可:

    # 左右节点
    root.left = self.buildTree(left_preorder,left_inorder)
    root.right = self.buildTree(right_preorder,right_inorder)

        (4)汇总

class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        # 先来处理递归跳出的条件/处理特殊情况
        if not preorder:
            return None
        
        # 创建根节点,先序数组中的第一个是根节点
        root = TreeNode(preorder[0])

        # 确定切分中序数组的下标
        split_index = inorder.index(root.val)

        # 确定左和右的中序数组
        left_inorder = inorder[:split_index]
        right_inorder = inorder[split_index+1:]

        # 根据前序和中序数组的左右长度必然相同,对前序数组进行切分
        left_preorder = preorder[1:len(left_inorder)+1]
        right_preorder = preorder[len(left_inorder)+1:]

        # 左右节点
        root.left = self.buildTree(left_preorder,left_inorder)
        root.right = self.buildTree(right_preorder,right_inorder)

        # 返回节点
        return root

3.从中序与后序序列构造二叉树

3.1 题目描述

3.2思路

这道题和第二道题异曲同工,要注意的地方就是对于序列切分的把控,这里不过多赘述

题解:

class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        # 递归终止条件/特殊情况讨论
        if not inorder:
            return None
        
        # 后序数组的最后一个元素就是根节点
        root = TreeNode(val = postorder[-1])

        # 中序数组切分索引
        split_index = inorder.index(root.val)

        # 对中序数组进行切分,右边会-1
        left_inorder = inorder[:split_index]
        right_inorder = inorder[split_index+1:]

        # 对后序数组进行切分(根据中序和后序数组长度必须相同进行切分)
        left_postorder = postorder[:len(left_inorder)]
        right_postorder = postorder[len(left_inorder):-1]

        # 左右节点
        root.left = self.buildTree(left_inorder,left_postorder)
        root.right = self.buildTree(right_inorder,right_postorder)
        
        # 返回值
        return root

4.将有序数组转换为二叉搜索树:

4.1 题目描述

4.2思路

相比于最大二叉树,这道题更为简单,因为所给的是有序数组,相信大家也能看出来,要想构造出平衡的二叉树,我们每次取有序数组的中节点作为根节点,然后递归地构建左子树和右子树即可。

代码如下:

class Solution(object):
    def sortedArrayToBST(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        if not nums:
            return None

        index_mid = len(nums) // 2

        root = TreeNode(nums[index_mid])

        root.left = self.sortedArrayToBST(nums[:index_mid])
        root.right = self.sortedArrayToBST(nums[index_mid+1:])

        return root

以上,学习在与总结和坚持,共勉

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值