思路:
我想到的做法有递归做法和深搜做法两种,
首先看子问题一:判断当前序列是否为一颗二叉搜索树或其镜像的前序遍历?我们根据二叉树搜索树的性质可知,序列中第一个点是二叉树的根,除根结点后的序列可以根据与根节点的大小关系将其分成两段序列,分别对应根节点左右子树的先序遍历序列。例如:8 6 5 7 10 8 11,我们第一次划分可知根节点为 8 ,左子树的先序序列为 6 5 7,右子树的先序序列为 10 8 11,也就是说,如果当前序列是否为一颗二叉搜索树或其镜像的前序遍历,那么那除根节点外的序列可以被分为两段!不断递归即可。
对于子问题二:输出后序遍历,比较简单,用一个栈在递归或搜索时不断存入根结点,最后利用栈的特点,输出即可。
测试点 7:
如果你将二叉树和二叉树的镜像混合判断了,那么会有一个测试点 7过不去(卡了我好久......),所谓不能混合判断就是:如果你确定这棵树不是镜像,就一直按照不是镜像来判断,不能一会按不是镜像来判断,一会按是镜像来判断。
AC 代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+5,INF = 0x3f3f3f3f;
int a[N],n;
stack<int> q;
bool check(int l,int r,int key) {
//cout<<l<<" "<<r<<endl;
if(l >= r) {
if(l == r)
q.push(a[l]);
return true;
}
else q.push(a[l]);
int x = a[l];
int i = l + 1,j = r;
if(key) {
while(a[i] >= x && i <= r) i ++;
while(a[j] < x && j > l) j --;
if(j + 1 == i) {
return check(i,r,key) && check(l + 1,j,key);
}
else return false;
}
else {
while(a[i] < x && i <= r) i ++;
while(a[j] >= x && j > l) j --;
if(j + 1 == i) {
return check(i,r,key) && check(l + 1,j,key);
}
else return false;
}
}
int main() {
cin>>n;
for(int i = 1; i <= n; i ++) {
cin>>a[i];
}
int key = 0;
if(a[2] > a[1]) key = 1;
if(check(1,n,key)) {
cout<<"YES"<<endl;
while(q.size() > 1) {
cout<<q.top()<<" ";
q.pop();
}
if(!q.empty())
cout<<q.top();
}
else cout<<"NO";
return 0;
}