题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历都不含重复的数字。
例:
输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8};中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建为下面的二叉树,并返回根节点。
思路
- 前序遍历输出的顺序是根节点-左树-右树,中序遍历输出的顺序是左树-根-右树。因此,我们可以从前序的顺序中找到根节点,用节点去中序中划分左树和右树。再对左树和右树递归处理。
- 时间复杂度:T(n) = T(n-1) + O(n),一次递归找到一个节点,寻找索引值需要O(n)。
- 空间复杂度:O(tree_height),递归的最大深度为树的高度,考虑只有左树或右树的最差情况,为O(n)。
代码
简单的写法:递归调用时,传入新列表(分片)。时间复杂度:O(n^2),空间复杂度O(n^2)
每次递归处理左子树和右子树时,向其传入了一个新列表,多使用了O(n)的空间。但是代码比较简洁。
def construct_binary_tree(preorder, inorder):
"""
more space need but simple coding
:param preorder:preorder traversal printout
:param inorder:inorder traversal printout
:return:root
"""
def construct_recursion(preorder, inorder):
if not preorder:
return None
root = TreeNode(preorder[0])
if preorder[0] in inorder:
# preorder not match inorder
i = inorder.index(preorder[0])
else:
# print('This is not a binary tree!')
# or raise exception
nonlocal match_flag
match_flag = False
return None
root.left = construct_recursion(preorder[1:i+1],inorder[:i])
root.right = construct_recursion(preorder[i+1:], inorder[i+1:])
return root
if preorder:
# empty input
match_flag = True
root = construct_recursion(preorder, inorder)
return root if match_flag else print('Invalid Input')
else:
return print('EMPTY INPUT')
稍稍修改:递归调用时,传入索引值。时间复杂度:O(n),空间复杂度O(n)
def construct_binary_tree2(preorder, inorder):
"""
do not trans new list
:param preorder: preorder traversal printout
:param inorder: inorder traversal printout
:param left: left index of list of this child tree
:param right: right index of this child tree
:return: root
"""
def construct_recursion(preorder, l_pre, r_pre, inorder, l_in, r_in):
"""
:param preorder: preorder of binary tree
:param l_pre: start index of subtree's preorder
:param r_pre: end index of subtree's preorder
:param inorder: inorder of binary tree
:param l_in: start index of subtree's inorder
:param r_in: end index of subtree's inorder
:return: current node
"""
if l_pre == r_pre:
# single node & end recursion
return TreeNode(preorder[l_pre])
elif l_pre > r_pre:
# prevent outing of range
return None
val = preorder[l_pre]
root = TreeNode(val)
if val in inorder[l_in:r_in+1]:
i = inorder[l_in:r_in+1].index(val)
else:
raise Exception('Invalid Input: Not A Binary Tree')
root.left = construct_recursion(preorder, l_pre+1, l_pre+i, inorder, l_in, l_in+i-1)
root.right = construct_recursion(preorder, l_pre+i+1, r_pre, inorder, l_in+i+1, r_in)
return root
if preorder:
root = construct_recursion(preorder, 0, len(preorder)-1, inorder, 0, len(inorder)-1)
return root
else:
raise Exception('EMPTY INPUT!')
思考
思路想明白了代码还是比较容易完成的。麻烦的主要在于无效输入的处理。
- 空输入。
- 前序和中序中元素不相同。
- 前序和中序中元素相同,但顺序不匹配。
三种情况应当可以抛出异常,并在异常中能做不同描述。
我的实现中未使用异常,使得代码凌乱。用了nolocal关键词,修改了上层函数中的变量,感觉不是很好。
附TreeNode定义:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
LeetCode 105. 从前序与中序遍历序列构造二叉树
- 代码1较慢:300ms
- 代码2优化了空间结构:200ms
- 而对于LeetCode,题目的输入必是一棵树,因此不用考虑处理输入构成不了树的情况。可以用下面的代码利用哈希表优化时间复杂度为O(n):64ms
代码
class Solution:
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
def construct_recursion(preorder, l_pre, r_pre, inorder, l_in, r_in):
if l_pre == r_pre:
# single node & end recursion
return TreeNode(preorder[l_pre])
elif l_pre > r_pre:
# prevent outing of range
return None
val = preorder[l_pre]
root = TreeNode(val)
# if val in inorder[l_in:r_in+1]: no need to check
i = index[val] # use hash table to find index in O(1)
d_pre_in = i - l_in
root.left = construct_recursion(preorder, l_pre+1, l_pre+ d_pre_in, inorder, l_in, i-1)
root.right = construct_recursion(preorder, l_pre+ d_pre_in+1, r_pre, inorder, i+1, r_in)
return root
if preorder:
index = {value:index for index, value in enumerate(inorder)} # key to optimize
# O(n) to set up hash table
root = construct_recursion(preorder, 0, len(preorder)-1, inorder, 0, len(inorder)-1)
# O(n) to rebulid tree
return root
# total O(n)
else:
return None
类似题目
LeetCode 106. 从中序与后序遍历序列构造二叉树
题目
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
代码
# 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
"""
def recursion(in_start, in_end, post_start, post_end):
if in_start > in_end:
return None
val = postorder[post_end]
root = TreeNode(val)
in_i = in_index[val]
post_i = in_i - in_start + post_start - 1
root.left = recursion(in_start, in_i-1, post_start, post_i)
root.right = recursion(in_i+1, in_end, post_i+1, post_end-1)
return root
if not inorder or not postorder:
return None
else:
in_index = {value:index for index, value in enumerate(inorder)}
return recursion(0, len(inorder)-1, 0, len(postorder)-1)