题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
算法背景:
前序遍历递归算法:NLR 先访问根结点N,再遍历左子树L,再遍历右子树R。
中序遍历递归算法:LNR 先访问左子树L,再访问根结点,再遍历右子树R。
根据前序遍历和中序遍历可以确定二叉树:
- 前序序列第一个结点确定二叉树的根结点
- 根据根结点在中序序列中的位置,前部分为根结点的左子树,后部分分为根结点的右子树。
- 再对分割出来的左子树和右子树进行递归分析。
案例:
前序遍历序列为ABCDEFGHI,中序遍历序列为BCAEDGHFI。
![图片说明](https://i-blog.csdnimg.cn/blog_migrate/aeab889cb34154028b1aec9744c8aa1d.png)
pre序列首元素必为二叉树的根结点,在vin序列中找到相应位置gen确定根结点,由于vin是LNR的特征,gen前的序列为左子树中序序列,gen后的序列为右子树中序序列。同样在pre序列中,gen+1前的序列为左子树的前序序列,gen+1后的序列为右子树的前序序列,然后利用子树的前序序列和中序序列递归求出二叉树。
![img](https://i-blog.csdnimg.cn/blog_migrate/f9a61c4f8034abf99e482ca44eab0a4c.png)
算法:
-
由先序序列第一个**
pre[0]
在中序序列中找到根节点位置gen
** -
以
gen
为中心遍历-
0~gen
左子树
- 子中序序列:
0~gen-1
,放入**vin_left[]
** - 子先序序列:
1~gen
放入pre_left[]
,**+1
**可以看图,因为头部有根节点
- 子中序序列:
-
gen+1~vinlen
为右子树
- 子中序序列:
gen+1 ~ vinlen-1
放入vin_right[]
- 子先序序列:
gen+1 ~ vinlen-1
放入pre_right[]
- 子中序序列:
-
-
由先序序列**
pre[0]
**创建根节点 -
连接左子树,按照左子树子序列递归(
pre_left[]
和vin_left[]
) -
连接右子树,按照右子树子序列递归(
pre_right[]
和vin_right[]
) -
返回根节点
时间复杂度O(n),空间复杂度O(n)。
/**
* 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) {
int vinlen = vin.size();
if (vinlen == 0)
{
return NULL;
}
vector<int> pre_left, pre_right, vin_left, vin_right;
TreeNode* root = new TreeNode(pre[0]);
int index = 0;
for (int i = 0; i < vinlen; ++i)
{
if (vin[i] == pre[0])
{
index = i;
break;
}
}
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 < vinlen; ++i)
{
vin_right.push_back(vin[i]);
pre_right.push_back(pre[i]);
}
root->left = reConstructBinaryTree(pre_left, vin_left);
root->right = reConstructBinaryTree(pre_right, vin_right);
return root;
}
};