问题描述:
input:两个数组pre,vin
output:指向重建出的二叉树的根节点的指针root
根据二叉树的前序和中序遍历得到的数组,重建出二叉树
解法:
思想:
递归建立二叉树的左右子树
利用前序遍历序列的特点:第一个数即为左(右)子树的根节点
利用中序遍历序列的特点:根节点将整个序列划分为左右子树
利用中序遍历序列确定左右子树节点的数量
步骤:
(1)根据在前序序列中得到的根节点,并在中序序列中找到根节点所在的位置
(2)根节点将中序序列分为左右两部分,根据左右子树中节点的数量,在前序序列中也找到左右子树节点的划分
(3)递归建立当前节点的左右子树(通过将pre和vin的节点索引传入)
own:
/**
* 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(pre.size() == 0)
return NULL;
TreeNode* root = NULL;
root = helper(pre, vin, 0, pre.size() - 1, 0, vin.size() - 1);
return root;
}
//递归建树
TreeNode* helper(const vector<int> &pre,
const vector<int> &vin,
int b1, int e1,
int b2, int e2
)
{
if(b1 > e1 && b2 > e2)
return NULL;
TreeNode* root = new TreeNode(pre[b1]);
if(b1 == e1)
return root;
//在中序数组中查找根节点
int sub_root;
for(int i = 0; i < vin.size(); i++)
{
if(vin[i] == pre[b1])
{
sub_root = i;
break;
}
}
root->left = helper(pre, vin, b1 + 1, b1 + sub_root - b2, b2, sub_root - 1);
root->right = helper(pre, vin, b1 + sub_root - b2 + 1, e1, sub_root + 1, e2);
return root;
}
};
剑指offer:
注意当子树的节点数量为1时,直接返回新建的节点,递归终止;记得判断此时pre和vin中的这个节点值是否相同,如果不相同说明pre或者vin数组错误,要抛出异常
/**
* 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(pre.size() == 0 || vin.size() == 0)
return NULL;
TreeNode* root = NULL;
root = helper(pre, vin, 0, pre.size() - 1, 0, vin.size() - 1);
return root;
}
//递归建树
TreeNode* helper(const vector<int> &pre,
const vector<int> &vin,
int b1, int e1,
int b2, int e2
)
{
if(b1 > e1 && b2 > e2)
return NULL;
TreeNode* root = new TreeNode(pre[b1]);
//***********************change1
//if(b1 == e1)
// return root;
if(b1 == e1)
{
if(b2 == e2 && pre[b1] == vin[b2])
{
return root;
}
else
{
throw "invaild input";
}
}
//***********************change1
//在中序数组中查找根节点
int sub_root = b1;//***********************
for(int i = 0; i < vin.size(); i++)
{
if(vin[i] == pre[b1])
{
sub_root = i;
break;
}
}
//***********************change2
//注意input数组错误的问题,在中序序列里找不到对应节点
if(sub_root == e2 && vin[sub_root] != pre[b1])
throw "invaild input";
//***********************change2
//***********************change3
//让代码更整洁易读
int leftsub_length = sub_root - b2;
int leftsub_end = b1 + leftsub_length;
//***********************change3
if(leftsub_length > 0)//***********************加入条件判断
{
root->left = helper(pre, vin, b1 + 1, leftsub_end, b2, sub_root - 1);
}
int rightsub_length = e2 - b2 - leftsub_length;
if(rightsub_length > 0)//***********************加入条件判断
{
root->right = helper(pre, vin, leftsub_end + 1, e1, sub_root + 1, e2);
}
return root;
}
};