L2-004. 这是二叉搜索树吗?
时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,
- 其左子树中所有结点的键值小于该结点的键值;
- 其右子树中所有结点的键值大于等于该结点的键值;
- 其左右子树都是二叉搜索树。
所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。
给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。
输入格式:
输入的第一行给出正整数N(<=1000)。随后一行给出N个整数键值,其间以空格分隔。
输出格式:
如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出“YES”,然后在下一行输出该树后序遍历的结果。数字间有1个空格,一行的首尾不得有多余空格。若答案是否,则输出“NO”。
输入样例1:7 8 6 5 7 10 8 11输出样例1:
YES 5 7 6 8 11 10 8输入样例2:
7 8 10 11 8 6 7 5输出样例2:
YES 11 8 10 7 5 6 8输入样例3:
7 8 6 8 5 10 9 11输出样例3:
NO
关于二叉树怎么建怎么遍历不是很熟悉了
算是很好的一道复习的题目
递归建树 递归遍历
然而还是看了题解
第一个思路是先建树 然后对这个树前序遍历 和原来的数组比较
然后再后序遍历树
有一组段错误 应该是runtime error
大概是递归太多爆栈了?
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std;
int n;
int vis[10005];
int tree[10005];
int num[10005];
void build(int rt, int x)
{
if(!vis[rt]){
vis[rt] = true;
tree[rt] = x;
return ;
}
if(x >= tree[rt]){
build(2 * rt + 1, x);
}
else{
build(2 * rt, x);
}
}
bool flag;
int cnt;
void qianxv(int k)
{
if(flag == 0)return ;
if(tree[k] == num[cnt]){
cnt++;
if(vis[2 * k]) qianxv(2 * k);
if(vis[2 * k + 1]) qianxv(2 * k + 1);
}
else
flag = 0;
return;
}
void re_qianxv(int k)
{
if(flag == 0) return ;
if(tree[k] == num[cnt]){
cnt++;
if(vis[2 * k + 1])re_qianxv(2 * k + 1);
if(vis[2 * k])re_qianxv(2 * k);
}
else flag = 0;
return ;
}
void print(int k)
{
if(vis[2 * k])print(2 * k);
if(vis[2 * k + 1]) print(2 * k + 1);
if(k == 1){
printf("%d
", tree[k]);
}
else{
printf("%d ", tree[k]);
}
return;
}
void reprint(int k)
{
if(vis[2 * k + 1])reprint(2 * k + 1);
if(vis[2 * k])reprint(2 * k);
if(k == 1){
printf("%d
", tree[k]);
}
else{
printf("%d ", tree[k]);
}
return;
}
int main()
{
while(cin>>n){
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++){
cin>>num[i];
build(1, num[i]);
}
flag = true;
cnt = 1;
qianxv(1);
if(flag){
printf("YES
");
print(1);
}
else{
flag = true;
cnt = 1;
re_qianxv(1);
if(flag){
printf("YES
");
reprint(1);
}
else{
printf("NO
");
}
}
}
return 0;
}
第二个思路是区间递归
前序的话根节点肯定在前面 然后后面跟了一段都比他小 在后面跟了一段都比他大 找到那个分界点
类似于快排的partition?
如果找到那个点 两段中间还差一大段说明这个不是前序遍历的
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std;
int n;
int num[1005];
bool isMirror;
vector<int>tree;
void f(int l, int r)
{
if(l > r) return;
int tr = l + 1;//tr - r是右子树
int tl = r;//l + 1 - tl是左子树
if(!isMirror){
while(tr <= r && num[tr] < num[l]) tr++;
while(tl > l && num[tl] >= num[l]) tl--;
}
else{
while(tr <= r && num[tr] >= num[l]) tr++;
while(tl > l && num[tl] < num[l]) tl--;
}
if(tr - tl != 1) return;
f(l + 1, tl);
f(tr, r);
tree.push_back(num[l]);
}
int main()
{
while(cin>>n){
tree.clear();
for(int i = 0; i < n; i++){
cin>>num[i];
}
isMirror = 0;
f(0, n - 1);
if(tree.size() != n){
isMirror = 1;
tree.clear();
f(0, n - 1);
}
if(tree.size() != n){
printf("NO
");
}
else{
printf("YES
%d", tree[0]);
for(int i = 1; i < n; i++){
printf(" %d", tree[i]);
}
cout<<endl;
}
}
return 0;
}