leetcode 第105题(从前序与中序遍历序列构造二叉树) ,第106题(从中序与后序遍历序列构造二叉树)python解法(用时40ms)
先从105题开始:
第105题是利用前序和中序恢复二叉树,主要还是应用递归的思想。
首先看一个简单的例子,在如下树中:
由于前序遍历第一个数是父节点的值(1),所以将其构造成一个节点。接下来,在中序遍历中找到这个值的索引(5),那么这个索引将中序遍历分成了两个部分[9,8,4,2,5] , [11,10,6,3,7,12,13,14](题目中说树中所有的值只出现一次,所以索引是唯一的)。在划分的过程中要注意能否将中序切割成两部分(因为可能是中序的第一个数或者最后一个数),如果只能切割成一部分,说明该父节点只有一个孩子。
切割成两部分后,接下来就递归了,在递归时buildTree()函数的第二参数inorder即为切割开的中序遍历的每个部分,而第一个参数preorder也要做出相应的改变。在中序遍历中,在父节点1前面的五个数全部是左子树的值,与前序遍历1后面的五个数对应。所以左子树的前序遍历即为前序遍历1后面的五位[2,4,8,9,5]。同样,接下来的[3,6,10,11,7,12,13,14]为右子树的前序遍历。将这两个前序遍历分别作为递归函数的第一个参数。
上面的方法很常见,关键是怎样去减少递归的次数。下面是我的方法,首先看第一种特殊情况,即整个树只包含左子树,如下图。
从这里可以看出,如果树的节点全部为左节点,那么它的中序遍历和后序遍历正好相反。
同样如果整个树只包含右节点,如下图所示:
与全部为左节点的情况正好相反,此时中序遍历和前序遍历相同。
所以,接下来在构造树的过程中,如果遇到这两种情况,即中序遍历和前序遍历正好相同或正好相反时,就无需再向下遍历,因为是全部左子树或右子树。而且这么做有一个最大的好处,就是当整个树只有左节点或右节点时,不需要遍历,就能直接构造出整个树。在这个题中最后一个测试用例就是这样的,是一个节点特别多的,全部由左节点构成的树,如果选择遍历,则会出现超时的情况。
下面是具体的代码,python实现。
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if inorder:
if inorder == preorder: # 全部为右节点
temp = None
for value in inorder[::-1]:
node = TreeNode(value)
node.right = temp
temp = node
return temp
if inorder == preorder[::-1]: # 全部为左节点
temp = None
for value in inorder:
node = TreeNode(value)
node.left = temp
temp = node
return temp
first = preorder[0]
node = TreeNode(first)
inorderIndex = inorder.index(first)
if inorderIndex > 0:
node.left = self.buildTree(preorder[1:inorderIndex+1], inorder[:inorderIndex])
if inorderIndex < len(inorder)-1:
node.right = self.buildTree(preorder[inorderIndex+1:], inorder[inorderIndex+1:])
return node
这种方法通过了全部的测试用例,并用时40ms。
然后是106题:
106题是用后序与中序构造树,与105题思路一样,使用递归,然后判断postorder与inorder的相等关系来减少遍历次数(注意,这与105题切割的方法有一些不同,可以尝试自己推一推)。下面是具体的代码:
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 inorder == postorder: # 全部为左节点
temp = None
for value in inorder:
node = TreeNode(value)
node.left = temp
temp = node
return temp
elif inorder[::-1] == postorder: # 全部为右节点
temp = None
for value in postorder:
node = TreeNode(value)
node.right = temp
temp = node
return temp
last = postorder[-1]
node = TreeNode(last)
inorderIndex = inorder.index(last)
print(inorderIndex)
if inorderIndex > 0:
node.left = self.buildTree(inorder[:inorderIndex], postorder[:inorderIndex])
if inorderIndex < len(inorder) - 1:
node.right = self.buildTree(inorder[inorderIndex+1:], postorder[inorderIndex:len(postorder)-1])
return node
也是只是用40ms就完成了全部测试用例。