记录下卡住的题目
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
1.先序第一个就是根节点
2.利用根节点可以把中序的成员分成左节点和右节点
3.左边节点所有成员个数确定后,可以在先序中找到一组属于左节点的数,临时称为L1,右边为R1
4.L1中第一个数便是L1的根节点,R1同理。
5.接着同样进行第二三步,利用中序的成员,就能分成左边组L2和右边组R2,若无就为空
6.接着继续找到L2第一个为根节点,R2同理,直到LN和RN个数均为0
实际上按照思路来说,难的地方应该是最后的递归和递归边界问题,可惜本人中间那几步写的时候由于不注意,还是写错了,导致debug了好久,还一度怀疑是递归写错了。
C++代码如下(刷题平台:牛客网):
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() == 0)//递归终止条件
return NULL;
TreeNode * root = new TreeNode(pre.front());//根节点
//求得左右先序中序
vector<int>m_lv;//左边,中序
vector<int>m_rv;//右边,中序
vector<int>::iterator itr_v;
int flag =0;
for(itr_v=vin.begin();itr_v != vin.end();itr_v++)
{
if(*itr_v == root->val)
flag =1;
else
{
if(flag ==0)
m_lv.push_back(*itr_v);
else
m_rv.push_back(*itr_v);
}
}
vector<int>m_lp;//左边,先序
vector<int>m_rp;//右边,先序
vector<int>::iterator itr_p;
int count=0;
for(itr_p=pre.begin()+1;itr_p != pre.end();itr_p++,count++)
{
if(count<m_lv.size())
m_lp.push_back(*itr_p);
else
m_rp.push_back(*itr_p);
}
root->left = reConstructBinaryTree(m_lp,m_lv);
root->right = reConstructBinaryTree(m_rp,m_rv);
return root;
}
};
简化版(第二次做更新)
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() == 0)
return NULL;
int len = pre.size();
TreeNode* root = new TreeNode(pre[0]);//根节点
vector<int>pre_left,pre_right,vin_left,vin_right;
//寻找标志位(中间位置节点)
int flag = 0;
for(int i = 0; i < len; i++){
if(vin[i] == pre[0])
flag = i;
}
//分类
for(int i = 0; i < len; i++){
if(i < flag){
pre_left.push_back(pre[i+1]);
vin_left.push_back(vin[i]);
}
if(i > flag){
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;
}
};
优化改进:某大佬剑指offer的思路:https://cuijiahua.com/blog/learing-algorithm/basis/page/7/