v1 – 递归的方式
思路:
我们围绕一个关键的特性来解决这个任务:前序遍历的第一个结点可以认为是当前结点,当前结点在中序遍历中,会把中序结点分成左子树和右子树。换个说法,在中序遍历中,当前结点所在的位置往左,就是左子树,往右就是右子树。
这样我们根据这个思路,依次递归,就可以构建出最终的树。
时间复杂度:O(n*logn),因为每一次取到一个前序遍历的根节点,都需要在中序遍历中去找到对应的下标,这个搜索的过程复杂度是logN,因为每次送入大概都是N/2的长度。
空间复杂度:O(n)。不需要额外空间。
class Solution:
preList = []
def dfs(self, pre, vin):
if not pre:
return None
headNode = None
prenode = pre[0]
print(prenode, vin)
split = None
# split = vin.index(prenode)
for i, num in enumerate(vin):
if num == prenode:
split = i
break
if split is not None:
pre.pop(0)
headNode = TreeNode(prenode)
left, right = vin[:split], vin[split:]
if left:
headNode.left = self.dfs(pre, left)
if right:
headNode.right = self.dfs(pre, right)
return headNode
def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
# write code here
return self.dfs(pre, vin)
v1.2 – 递归的加速方案–hashMap
我们可以把所有节点的值在中序遍历的位置都存在字典里,之后的查询复杂度就是O(1),那样整个算法的复杂度就是O(n*1)
class Solution:
preList = []
def dfs(self, pre, vin, lf, rg):
if not pre:
return None
headNode = None
prenode = pre[0]
# print(prenode, vin)
split = None
# split = vin.index(prenode)
# for i, num in enumerate(vin):
# if num == prenode:
# split = i
# break
split = self.dict[prenode]
# print("find, ", split, lf, rg)
if split is not None and split>=lf and split<rg:
pre.pop(0)
headNode = TreeNode(prenode)
left, right = vin[:split-lf], vin[split-lf:]
if left:
headNode.left = self.dfs(pre, left, lf, split)
if right:
headNode.right = self.dfs(pre, right, split, rg)
return headNode
def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
# write code here
self.dict = {}
for i, num in enumerate(vin): #存储字典初始化
# print(i,num)
self.dict[num] = i
return self.dfs(pre, vin, 0 , len(vin))