leetcode 第105题(从前序与中序遍历序列构造二叉树) ,第106题(从中序与后序遍历序列构造二叉树)python解法(用时40ms)

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就完成了全部测试用例。

第一次写博客,有点紧脏,靴靴大家!!放一张老婆大人

猜你喜欢

转载自blog.csdn.net/Whyalwaysxu/article/details/84995750