![](https://img-blog.csdnimg.cn/img_convert/1a97b96e1490bbc605705d0b2ba0eb1b.png)
![](https://img-blog.csdnimg.cn/img_convert/179a557cfb037720dddf2f4e595d7d13.png)
这道题和洛谷不同的点有两个:
输入都是整数,不是连在一起的字符串。
输出是层序遍历,不是后序+中序求前序。
如果还想采用substr这种简单的做法就要先解决第一步。
定义两个string,把输入都串在一起
for(int i=0;i<n;++i)
cin>>t,back+=t+48;
for(int i=0;i<n;++i)
cin>>t,mid+=t+48;
完事之后根据根集分出左右子树集合,当然分树的前提是有子树可分。
void travel(string back_,string mid_){
if(mid_.length()>0){//有子树可分
char root=back_[back_.length()-1];//后序,则最后一个是根节点
int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
travel(back_.substr(0,k),mid_.substr(0,k));
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
}
}
因为下标是从0开始的,所以从0开始取k个,和从k位置开始取几个,这两个k的含义是有所区别的。
即下标k=5的位置实际长度是6。
画图可得左右子树划分的范围↓
再根据左右子树范围找出这些子树在根集中的范围即可
![](https://img-blog.csdnimg.cn/img_convert/6197599675b2333238d4582959c90ee5.png)
所以不管什么情况,中序的右边都是k+1开始全部取,而后序是k+1的地方开始取限定范围的根(也是画图可得)
上面那串代码就变成了递归这颗树。
譬如在下面不同位置放上cout<<root就可以实现先序遍历或者中序和后序
void travel(string back_,string mid_){
if(mid_.length()>0){//有子树可分
char root=back_[back_.length()-1];//后序,则最后一个是根节点
int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
//cout<<root 先序遍历
travel(back_.substr(0,k),mid_.substr(0,k));
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
}
}
void travel(string back_,string mid_){
if(mid_.length()>0){//有子树可分
char root=back_[back_.length()-1];//后序,则最后一个是根节点
int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
travel(back_.substr(0,k),mid_.substr(0,k));
//cout<<root 中序遍历
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
}
}
由于求的是层次遍历,所以要对代码稍作修改。
根据二叉树的结构可知,往左子树走的时候深度加1,往右子树去的时候深度先减1再加1,回来的时候再减1。
![](https://img-blog.csdnimg.cn/img_convert/bcc555cdfaa716226f535043be989c31.png)
void travel(string back_,string mid_,int level){
if(mid_.length()>0){//有子树可分
char root=back_[back_.length()-1];//后序,则最后一个是根节点
int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
level++;
travel(back_.substr(0,k),mid_.substr(0,k));
level--;
level++;
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
level--;
}
}
一眼顶真发现第八行先减,第十行再加重复了,直接删掉这两行即可,再用一个vector<int>ans[level]
动态存储每一行的答案即可。
void travel(string back_,string mid_,int level){
if(mid_.length()>0){
char root=back_[back_.length()-1];
int k=mid_.find(root);
ans[level].push_back(root-48);
level++;
travel(back_.substr(0,k),mid_.substr(0,k),level);
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1),level);
level--;
}
}
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=31;
string back,mid;
int n,t,tree[31];
vector<int>ans[50];
void travel(string back_,string mid_,int level){
if(mid_.length()>0){
char root=back_[back_.length()-1];
int k=mid_.find(root);
ans[level].push_back(root-48);
level++;
travel(back_.substr(0,k),mid_.substr(0,k),level);
travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1),level);
level--;
}
}
int main(){
cin>>n;
for(int i=0;i<n;++i)
cin>>t,back+=t+48;
for(int i=0;i<n;++i)
cin>>t,mid+=t+48;
travel(back,mid,1);
for(int i=1;i<50;++i)
for(auto j:ans[i])
cout<<j<<" ";
return 0;
}
按层输出所以要对二叉树的结构有清晰的认知才能做出来,比洛谷的稍微难一点。