刚好这一题让我的树的理解更加深刻。
题目的意思是如果给你先序序列和后序序列是否能够构建出唯一一棵树,如果不能请输出序号最小的,如果可以,那么请输出唯一的那一棵树的中序序列。
我们不妨把题目的所以的样子的树给画出来。画出来的结果可能是存在一下两种情况。
所以这个树不唯一。
我们在其中找出规律,其实里面是存在规律的。这个题目最不好的地方是,判定为no的数字序列给的数据很小,可能找规律好像不太好找。
关于的树的先序,中序和后序遍历顺序相信写pat的人应该很熟悉。
先序序列的第一个数的为根节点(左子树和右子树的序列分别在根节点的后面):比如在这个示例中1为跟根节点。后序序列的最后一个数为根节点。
我们在其中发现到的规律如下(可能会有一点点绕,请耐心阅读,你会发现很简单的):根节点前面的一个点我们记为θ。那么我们现在返回先序序列去寻找,然后我们到θ前的树都是根节点的左子树,右子树同样。如果我们在现在序列找θ,发现θ前并没有数,那么表示这个序列是不唯一的。
结合题目所以的样子我们解释一下:
1 2 3 4
2 4 3 1
根节点前面的一个点为3.我们现在返回先序序列去寻找,发现3存在一个数是2,那么2就是先序序列的左子树。那么我们现在得出的结论是2是根节点的左子序列,3,4是右子序列。我们接着选取3,在先序序列中寻找,发现3前面没有子树。所以序列不唯一。所以序列是不唯一的。
那么说了这么多,我们再看代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> pre,in,post;
int n;
bool f=true;
void inorder(int preL,int preR,int postL,int postR){
if(preL==preR){
in.push_back(pre[preL]);
return;
}
if(pre[preL]==post[postR]){
int i=preL+1;
while(i<=preR&&pre[i]!=post[postR-1]) i++;//找到先序序列的左子树
//存在左子树才去对左子树去进行遍历
if(i-preL>1) inorder(preL+1,i-1,postL,postL+(i-1)-(preL+1));//该情况是存在左子树
else f=false;//如果上面的if不成立,就表示没有左子树。显然序列不唯一
in.push_back(post[postR]);
inorder(i,preR,postL+(i-1)+(preL+1)-1,postR-1);
}
}
int main(){
cin>>n;
pre.resize(n),post.resize(n);
for(int i=0;i<n;i++) cin>>pre[i];
for(int i=0;i<n;i++) cin>>post[i];
inorder(0,n-1,0,n-1);
if(f) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
cout<<in[0];
for(int i=1;i<in.size();i++) cout<<' '<<in[i];
cout<<endl;
return 0;
}