题目链接是:
https://www.patest.cn/contests/gplt/L2-004
题解:
根节点的值是位于左右子树之间的,即大于左子树的所有值,但是小于等于右子树的所有值。
而先序遍历的序列,第一个值就是其根的值,我们可以利用这些性质来递归判断一棵树是否为二叉搜索树。
首先,遍历这个序列,找到第一个大于等于根节点值的节点,如果从这个节点开始之后的所有节点的值都是大于等于根节点的,那么这
棵树就是二叉搜索树。而二叉搜索树的“镜像”也可以利用这种思想进行判断。
如果是一棵二叉搜索树或者是其镜像,我们就可以开始建树,建树之后可以递归的输出其后序遍历序列。
代码及注释:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1000+10;
struct Node
{
int value;
Node *lson, *rson;
Node():lson(NULL),rson(NULL){}
}*root;
int n;
int s[maxn];
vector<int> ans; //按序记录后序遍历的元素,因为在后序遍历输出时不能控制最后的空格
//判断 kind为true判断原树,为false判断镜像
bool test(bool kind, int L, int R)
{
if(L >= R)
return true;
int i;
for(i = L+1; i <= R; i++)
{
if(kind)
{
if(s[L] <= s[i])
break; //到 i-1 为止为左子树
}
else
{
if(s[L] > s[i])
break;
}
}
bool flag = true;
for(int j = i; j <= R; j++)
{
if(kind)
{
if(s[j] < s[L])
flag = false; //若右子树有小于根结点值的直接返回 false
}
else
{
if(s[j] >= s[L])
flag = false;
}
}
if(flag)
return test(kind, L+1, i-1) && test(kind, i, R); //一直递归分治下去
else
return false;
}
Node* create(bool kind, int L, int R)
{
if(L > R)
return NULL;
int i;
for(i = L+1; i <= R; i++)
{
if(kind)
{
if(s[L] <= s[i])
break; //到i-1为止为左子树
}
else
{
if(s[L] > s[i])
break;
}
}
Node *p = new Node();
p->value = s[L];
p->lson = create(kind, L+1, i-1); //递归建立左子树
p->rson = create(kind, i, R); //递归建立右子树
return p;
}
void postOrderTraverse(Node *p)
{
if(p)
{
postOrderTraverse(p->lson);
postOrderTraverse(p->rson);
ans.push_back(p->value);
}
}
void Print()
{
postOrderTraverse(root);
int len = ans.size();
for(int i = 0; i < len-1; i++)
printf("%d ", ans[i]);
printf("%d\n", ans[len-1]);
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &s[i]);
int flag = 0;
if(test(true, 0, n-1))
{
flag = 1;
root = create(true, 0, n-1);
}
else if(test(false, 0, n-1))
{
flag = 2;
root = create(false, 0, n-1);
}
if(flag != 0)
{
puts("YES");
Print();
}
else
puts("NO");
return 0;
}