1119 Pre- and Post-order Traversals (30分)
题目大意:给定前序和后序,要求输出中序,并判断是否唯一。
首先要知道:
先序:根结点-> 左孩子 -> 右孩子
后序:从后往前: 根结点 -> 右孩子 -> 左孩子
首先找到根结点,(前序第一个和后序最后一个值为根)后序指针往前移动一位(先将其默认认为是根的右孩子结点),找到前序中对应的值:从前序的根出发直到找到该值(右孩子)中间经过的所有元素为根的左孩子,计算出左孩子的个数。 以此为依据便可以分别在前序和后序中划分左右孩子。
如果在寻找的过程中,左孩子为0,表明原来指定的右孩子可以为左孩子也可以为右孩子(无法确定)。
例如:
像这样的一棵树,其前序为:0123456,后序为2315640
-
第一步:此时0为根结点,后序往前一位(4)即为根结点的右孩子(先假设其为右孩子,也可能为左孩子),在前序中找到该结点,经过了三个结点(count),这三个结点在4之前出现,表明其在根的左边,此时可以确定4是右孩子。
如果123不存在,则无法确定4是左孩子还是右孩子(因此可以用count来判断是否唯一) -
第二步:递归地将其分为左右孩子,然后重复第一步(start1+1/end2-1为根结点)
左孩子:前序为:start1 +1 ~ start1+count+1;后序为:start2 ~ start2+count
右孩子:前序为:start1+count+1 ~ end1;后序为:start2+count ~ end2-1
#include<iostream> //输入输出流头文件
#include<vector> //变长数组容器
using namespace std; //标准命名空间
int n,isUnique=1;
vector<int> preorder,postorder,in;
void inorder(int s1,int e1,int s2,int e2);
int main(){ //主函数
#ifdef ONLINE_JUDGE //如果有oj系统(在线判定),则忽略文件读入,否则使用文件作为标准输入
#else
freopen("1.txt", "r", stdin); //从1.txt输入数据
#endif
cin>>n;
preorder.resize(n);
postorder.resize(n);
for(int i=0;i<n;i++) cin>>preorder[i];
for(int i=0;i<n;i++) cin>>postorder[i];
inorder(0,n-1,0,n-1);
if(isUnique) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
for(int i=0;i<n;i++){
cout<<in[i];
if(i<n-1)cout<<' ';
else cout<<endl;
}
return 0; //返回0,如果不返回0,PAT会报错
}
void inorder(int s1,int e1,int s2,int e2){
if(s1>e1)return ;//越界
if(s1==e1) {//此时为叶子结点
in.push_back(preorder[s1]);
return ;
}
int count=0;
while(s1+count<e1){
if(preorder[s1+count]==postorder[e2-1]) break;
count++;
}
if(count<2)isUnique=0;
else inorder(s1+1,s1+count-1,s2,s2+count-2);//左孩子
in.push_back(postorder[e2]);
inorder(s1+count,e1,s2+count-1,e2-1);
}