[leetcode] 106. 从中序与后序遍历序列构造二叉树

题目

根据一棵树的中序遍历与后序遍历构造二叉树。假设树中没有重复的元素。

样例:

输入
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
输出
[3,9,20,null,null,15,7]
在这里插入图片描述

递归,和 [leetcode]105 即 [剑指offer] 07 思路一模一样。

构建二叉树的大问题,可以分解成构建左、右子树的两个小问题,而小问题和大问题又在本质上是一致的,因此可以用递归解决。

二叉树递归的思想:左、右子树的解,构成了二叉树的解。

和105不同的是,这里如果使用了postorder 的pop,则必须先递归解决右子树, 原因是 postorder 的pop顺序是根节点---->右子节点---->左子节点。而之前的105题,preorder的pop(0)顺序是根节点---->左子节点---->右子节点。
在这里插入图片描述

算法1:在递归方法中,传入数组的拷贝

递归终止条件是:postorder(inorder)为空
递归过程中传递 postorder 和 inorder 是采用切片的方式,需要复制数组,时间、空间复杂度大

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if not (inorder and postorder):
            return None
        root=postorder.pop() # 这里pop所以后面不需切片postorder
        idx=inorder.index(root)
        root=TreeNode(root)
        root.right=self.buildTree(inorder[idx+1:],postorder)
        root.left=self.buildTree(inorder[:idx],postorder)
        return root
        
   ############## 另一种写法 #################
   class Solution:
    def buildTree(self, inorder, postorder):
        # 实际上inorder 和 postorder一定是同时为空的,因此无论判断哪个都行
        if not (inorder and postorder):
            return None
        # 这里没pop,因此后面要切片post,且先left/right都可以
        root = TreeNode(postorder[-1])  
        i = inorder.index(root.val)
        root.left = self.buildTree(inorder[:i], postorder[:i])
        root.right = self.buildTree(inorder[i+1:], postorder[i:-1])
        return root		

复杂度分析:

时间复杂度:O(NlogN),这里 N 是二叉树的结点个数,算法中每个结点都会被看到一次,是线性级别的,递归的深度是对数级别的,因此时间复杂度是 O(NlogN)。
空间复杂度:O(N),构造一棵树需要 N个结点(待讨论)。

思路2:在递归方法中,传入子数组的边界索引

【1】创建 hashmap 存储中序遍历的序列:value -> its index 。
【2】定义辅助函数helper,参数是中序序列中当前子树的左右边界left,right。
【3】递归终止条件是left>right, 也就是子树为空。
【4】递归过程,假设根节点在中序遍历中索引为 index。递归创建右子树 helper(index + 1, right) 和左子树 helper(left, index - 1)。 然后return root。

class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        idx_map={val:i for i,val in enumerate(inorder)}
        def helper(left, right):
            if left > right:
                return None
            node = postorder.pop()
            root = TreeNode(node)
            idx = idx_map[node]   ## 此处node是value,但root是一个对象
            root.right = helper(idx+1, right)
            root.left = helper(left, idx-1)
            return root
        return helper(0, len(inorder)-1 ) 

我的错误点!
[1] node=postorder.pop()是一个值,而root=TreeNode(node)是一个类的实例对象,因此不可以idx=idx_map[root],应该idx=idx_map[node]
[2] def helper函数最后一定要return root,否则递归了半天最后什么都不输出
[3] 左子树的边界条件是(left, idx-1),和切片形式[ : idx]是一致的,因为在这里边界的初始值是0和len-1也就是两边都包,而切片是前包后不包

在这里插入图片描述
采用数组切片大约100ms,而传递边界值的算法效率非常高,28ms,两者内存占用差不多
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值