题目描述:


给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
alt
提示: 1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比


题解

思路:二叉树的前序遍历:根左右;中序遍历:左根右
由前序遍历知道根节点之后,能在中序遍历上划分出左子树和右子树。分别对中序遍历的左右子树递归进行这一过程即可建树。在划分过程中,重要的是对二叉树进行分割,既然要分割,就需要提前直到根节点的位置。


图示过程,引用Maokt

alt


代码

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if (0 == pre.size() || vin.empty()) 
            return NULL;//空树,也作为递归调用的出口
        
        //前序遍历,第一个元素即为根节点元素,通过构造函数创建根节点
        TreeNode* root = new TreeNode(pre[0]);
//         从后序遍历中找到根节点的位置,从这个位置开始将中序遍历的结果分为
//         左子树和右子树
        int index = 0;//找到根节点在中序遍历中的位置
        for (index;index<vin.size();index++) {
            if (vin[index] == pre[0])//找到中序遍历中根节点的位置
            break;
        }
        //使用vector拷贝构造函数分别得到递归调用时需要用到的四个vector区间
        //构造四个数组,分别存放先序遍历中的左子树和右子树,以及中序遍历中的左子树和右子树
        //注意:拷贝构造是左取右不取
//         vector<int> pre_left(pre.begin()+1,pre.begin()+index+1);
//         vector<int> pre_right(pre.begin()+index+1,pre.end());
//         vector<int> vin_left(vin.begin(),vin.begin()+index);
//         vector<int> vin_right(vin.begin()+index+1,vin.end());
        //上述代码也可直接进行,如
        //左子树
        vector<int> pre_left,pre_right,vin_left,vin_right;
        for(int i = 0;i<index;i++){
            pre_left.push_back(pre[i+1]);
            vin_left.push_back(vin[i]);
        }
        //右子树
        for(int i =index+1;i<pre.size();i++){
            pre_right.push_back(pre[i]);
            vin_right.push_back(vin[i]);
        }
        //递归构造左右子树
        root->left=reConstructBinaryTree(pre_left, vin_left);
        root->right=reConstructBinaryTree(pre_right, vin_right);
        return root;
    }
};