Leetcode 105:从前序与中序遍历序列构造二叉树(最详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/83343535

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解题思路

这是一个非常基础的问题。我们考虑这样一个简单的例子

preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]

我们知道preorder[0]就是二分搜索树的root,而且在inorder3的左边是左子树,而3的右边是右子树。接着用同样的方法找到左右子树的root即可。

class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        return self._buildTree(0, len(preorder)-1, 0, len(inorder)-1, preorder, inorder)
    
    def _buildTree(self, pre_start, pre_end, in_start, in_end, preorder, inorder):
        if pre_start > pre_end or in_start > in_end:
            return

        root = TreeNode(preorder[pre_start])
        ini, i = 0, in_start
        while i <= in_end:
            if inorder[i] == root.val:
                ini = i
            i += 1

        root.left = self._buildTree(pre_start+1, pre_end, in_start, ini-1, preorder, inorder)
        root.right = self._buildTree(pre_start+ini-in_start+1, pre_end, ini+1, in_end, preorder, inorder)
        return root  

实际上上面这种写法非常臃肿,我们有更为简洁的写法。

class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            ind = inorder.index(preorder.pop(0))
            root = TreeNode(inorder[ind])
            root.left = self.buildTree(preorder, inorder[0:ind])
            root.right = self.buildTree(preorder, inorder[ind+1:])
            return root

思路和第一种写法是一样的,关键在于寻找根节点。

同样对于递归可以解决的问题,我们都希望可以通过迭代去解决。对于迭代的关键还是在于找根节点。我们通过preorder知道3是整棵树的根节点,所以我们建立一个stack,然后将3加入到stack中。栈顶是我们每次要考虑的根节点,我们每次遍历preorder中的元素。我们首先考虑9应该放在哪?通过preorder我们知道9一定是root左子树的根节点,所以我们将9加入到root(3).left

stack: 3 9
    3
   / 
  9

我们接着判断9的左右孩子是谁?我们通过inorder发现9没有左右孩子,我们将9出栈。

stack: 3
    3
   / 
  9

我们接着考虑20应该放在哪。我们发现3的右边是空的,所以我们将20放到3的右边(通过preorder知道20一定是右孩子的根)。

stack: 3 20
    3
   / \
  9  20

我们接着考虑15应该放在哪。我们将15加入到20的左孩子(通过preorder),同时入栈。

stack: 3 20 15 
    3
   / \
  9  20
    /  
   15   

通过inorder我们知道15没有左右孩子,所以我们将15出栈。

stack: 3 20 15 
    3
   / \
  9  20
    /  
   15   

我们接着考虑7应该放在哪。我们返现20的右边是空,所以我们将7放到20的右边,同时将7入栈。

stack: 3 20 7
    3
   / \
  9  20
    /  \
   15   7

接着就是具体实现上的细节。

class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if not inorder or not preorder:
            return 
        
        root = TreeNode(preorder[0])
        stack = [root]
        i = 0
        
        for node in preorder[1:]:
            parent = stack[-1]
            
            if parent.val != inorder[i]:
                parent.left = TreeNode(node)
                stack.append(parent.left)     
            else:
                while stack and stack[-1].val == inorder[i]:
                    parent = stack.pop()
                    i += 1
                parent.right = TreeNode(node)
                stack.append(parent.right)
                
        return root

reference:

https://articles.leetcode.com/construct-binary-tree-from-inorder-and-preorder-postorder-traversal/

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/83343535