105. 从前序与中序遍历序列构造二叉树;106. 从中序与后序遍历序列构造二叉树

 

105. 从前序与中序遍历序列构造二叉树

2020/2/17:

C++:

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
13     {
14         TreeNode *root=func(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
15         return root;
16     }
17     TreeNode *func(vector<int>& preorder, vector<int>& inorder,int le_p,int ri_p,int le_i,int ri_i)
18     {
19         if(ri_p<le_p)
20         {
21             return nullptr;
22         }
23         TreeNode *root=new TreeNode(preorder[le_p]);
24         auto iter=find(inorder.begin(),inorder.end(),preorder[le_p]);
25         int distance=iter-1-inorder.begin()-le_i;
26         root->left=func(preorder,inorder,le_p+1,le_p+1+distance,le_i,le_i+distance);
27         root->right=func(preorder,inorder,le_p+1+distance+1,ri_p,le_i+distance+2,ri_i);
28         return root;
29     }
30 };

 


 

思路蛮简单的:前序序列首元素是根节点,然后在中序序列中找该值,左侧为左子树,右侧为右子树,对两个子树递归调用即可。
一开始写的:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
        root=TreeNode(preorder[0])
        index=inorder.index(preorder[0])
        root.left=self.buildTree(preorder[1:index+1],inorder[:index])
        root.right=self.buildTree(preorder[index+1:],inorder[index+1:])
        return root

花了大量时间在list的浅拷贝上,以及index()函数的过多使用。

官方题解的:
是用中序序列先做一个字典,然后每次查找根节点的index时就是O(1)的时间,以及递归函数参数中加上前后界,省去浅拷贝的时间。用了一个全局的变量,每次加一,即每次讲前序序列中第pre_idx 个数作为根,这个我想了半天,后来画了下递归过程,发现每次pre_idx 加一指示的正好是halper函数递归时要选取的根节点。。实在是有点取巧。。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        def helper(in_left = 0, in_right = len(inorder)):
            nonlocal pre_idx
            # if there is no elements to construct subtrees
            if in_left == in_right:
                return None
            
            # pick up pre_idx element as a root
            root_val = preorder[pre_idx]
            root = TreeNode(root_val)

            # root splits inorder list
            # into left and right subtrees
            index = idx_map[root_val]

            # recursion 
            pre_idx += 1
            # build left subtree
            root.left = helper(in_left, index)
            # build right subtree
            root.right = helper(index + 1, in_right)
            return root
        
        # start from first preorder element
        pre_idx = 0
        # build a hashmap value -> its index
        idx_map = {val:idx for idx, val in enumerate(inorder)} 
        return helper()

时间、空间差距:
在这里插入图片描述

106. 从中序与后序遍历序列构造二叉树

思路和上题一样,后序的最后是根节点,还是去中序里去找该节点,再递归左右子树。

1.copy上题的官方题解,不过这里递归过程是从后序序列末尾依次向前选取,那么全局那个变量也要从最后开始依次递减,并且递归时要先递归右子树,再递归左子树。

class Solution:
    def buildTree(self, inorder, postorder):
        def func(le=0,ri=len(postorder)):
            nonlocal x
            if ri-le<1:
                return None
            _val=postorder[x]
            x-=1
            root=TreeNode(_val)
            index=dic.get(_val)
            root.right=func(index+1,ri) #半闭半开
            #这俩顺序不能反
            root.left=func(le,index)    #半闭半开
            return root
        x=len(postorder)-1
        dic={value:key for key,value in enumerate(inorder)}
        return func()

2.自己写的,四个参数,分别指示两个序列当前考察的两段子序列范围。时间、空间使用情况和上面的写法是基本一致,但好理解一些。
注意这里递归子树时左右的先后就无所谓了,因为当前考察的两段中序、后序子序列范围已经明确给出了,不需要为了什么奇怪的全局变量改动代码布局。。。

class Solution:
    def buildTree(self, inorder, postorder):
        def func(in_le,in_ri,po_le,po_ri):
            if in_ri-in_le<1:
                return None
            val=postorder[po_ri-1]
            root=TreeNode(val)
            index=dic.get(val)
            root.left=func(in_le,index,po_le,po_le+index-in_le)
            root.right=func(index+1,in_ri,po_le+index-in_le,po_ri-1)
            return root
        dic={value:key for key,value in enumerate(inorder)}
        return func(0,len(inorder),0,len(postorder))
posted @ 2019-07-27 22:04  NeoZy  阅读(162)  评论(0编辑  收藏  举报