题目
根据一棵树的中序遍历与后序遍历构造二叉树。假设树中没有重复的元素。
样例:
输入
中序遍历 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,两者内存占用差不多