AcWing 1609. 前序和后序遍历
原题链接
中等
作者:
joykiller
,
2020-05-07 15:39:32
,
所有人可见
,
阅读 1232
算法
- 首先前序遍历的第二个点可能是左子树根或者右子树根;后续遍历倒数第二个节点也可能是左子树根或者右子树根
1.1. 如果这两个位置数值不同,那么前序第二个点是左子树根,后续倒数第二个点是右子树根
1.2. 如果数值相同则既有可能是左子树又有可能是右子树,判定为多解;放到左右子树都可以
- 在前序中定位到左子树的值,可以在后续中通过这个值得位置定位到左子树大小,递归处理即可
- 最后需要注意边界条件,集合没有点和只有一个点的情况
C++ 代码
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int N = 35;
int pre[N], post[N], n;
int l[N], r[N], v[N], idx;
bool multi=false;
map<int, int> pos;
vector<int> ans;
int newNode(int x) {
int t=++idx;
v[t]=x, l[t]=r[t]=-1;
return t;
}
int build(int prel, int prer, int postl, int postr) {
if(prel>prer) return -1;
if(prel==prer) return newNode(pre[prel]);
int rv=pre[prel];
int t=++idx;
v[t]=rv;
if(pre[prel+1]==post[postr-1]) {
multi=true;
l[t]=build(prel+1, prer, postl, postr-1);
r[t]=-1;
} else {
int index=pos[pre[prel+1]];
l[t]=build(prel+1, prel+(index-postl+1), postl, index);
r[t]=build(prel+(index-postl+1)+1, prer, index+1, postr-1);
}
return t;
}
void inOrder(int u) {
if(u==-1) return;
inOrder(l[u]);
ans.push_back(v[u]);
inOrder(r[u]);
}
int main() {
cin>>n;
for(int i=0;i<n;++i) cin>>pre[i];
for(int i=0;i<n;++i) {
cin>>post[i];
pos[post[i]]=i;
}
int root=-1;
root=build(0,n-1,0,n-1);
if(multi) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
inOrder(root);
cout<<ans[0];
for(int i=1;i<ans.size();++i) {
cout<<" "<<ans[i];
}
}