输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路1:前序序列第一个节点即为二叉树的根节点,以此根节点为中序序列中的分界点,分离出左子树和右子树,递归创建二叉树。

代码:

class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        //若前序和中序为空,则返回空树
        if(pre.empty()||vin.empty())
            return NULL;
        //创建根节点
        TreeNode *tRoot=new TreeNode(pre[0]);
        //在中序序列中找到根节点的位置,并记录左子树节点的数量
        int num_lchild;
        for(int i=0;i<vin.size();i++)
        {
            if(vin[i]==pre[0])
            {
                num_lchild=i;
                break;
            }
        }
        //若找到最后都没有找到对应的根节点,说明输入序列有问题
        if(vin[num_lchild]!=pre[0])
            return NULL;

        //若找到,则可以根据此根节点划分左右子树
        //递归构造左右子树
        vector<int> left_pre,right_pre,left_in,right_in;
        for(int i=0;i<num_lchild;i++)
        {
            left_pre.push_back(pre[i+1]);
            left_in.push_back(vin[i]);
        }
        for(int i=num_lchild+1;i<vin.size();i++)
        {
            right_pre.push_back(pre[i]);
            right_in.push_back(vin[i]);
        }
        //递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
        tRoot->left=reConstructBinaryTree(left_pre,left_in);
        tRoot->right=reConstructBinaryTree(right_pre,right_in);
        return tRoot;
    }
};

注意几点:

  1. 特殊处理:取根节点之前,判断前序和中序序列是否为空,若为空则返回空树;
    取根节点之后,遍历中序序列找出根节点的位置时,出现找不到对应节点的情况。
  2. 创建根节点时:TreeNode *tRoot=new TreeNode(pre[0]);里面的pre[0]相当于初始化tRoot->value=pre[0]的意思,具体情况根据节点定义确定。
  3. 构造左右子树前中序序列时注意区间划分。
  4. 别忘了返回值return tRoot.

2.递归算法:

思路都一样

TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
        if (pre.size() == 0 || vin.size() == 0)
            return nullptr;
        return reConstructBinaryTree(pre, 0, pre.size() - 1, vin,  0, vin.size() - 1);
    }

    TreeNode* reConstructBinaryTree(vector<int> &pre, int begin_pre, int end_pre,  vector<int> &vin, int begin_vin, int end_vin)
    {
        if (begin_pre>end_pre||begin_vin > end_vin)
            return nullptr;
        int rootVal = pre[begin_pre];
        TreeNode* root = new TreeNode(rootVal);
        int in = begin_vin;
        while (vin[in]!=rootVal&&in<=end_vin)
        {
            ++in;
        }
        //根据在中序找到的根节点,可以判断出左子树的元素个数为in-begin_vin。由此可以得出左右子树的起始点和终点
        root->left = reConstructBinaryTree(pre, begin_pre + 1, begin_pre + in-begin_vin, vin, begin_vin, in - 1);
        root->right = reConstructBinaryTree(pre, begin_pre + in + 1-begin_vin, end_pre, vin,in + 1, end_vin);
        return root;
    }