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
首先题外话 这题的镜像二叉树接触很多题目了
镜像二叉树递归打印的时候其实就是交换了左右子树调用顺序
题目思路 根据搜索二叉树的性质
肯定能用根把二叉树分成左右两部分 (下代码用check函数递归检查)
否则就不是标准的前序序列
镜像二叉树在这里其实就是左小右大倒过来判断
首先假设正常二叉树 然后不满足条件 假设是镜像二叉树
满足的条件就是 每棵树都一分为二
到最后last后序数组长度为n (理解很简单 例如 前序列5 1 2 7 4 9 10 中 7 4就没有进入后序序列)
详情见代码
#include <bits/stdc++.h>
using namespace std;
vector<int>p,last;
bool flag; ///1镜像
void check(int root,int End) ///根的位置 结束位置
{
if(root > End) return ;
int i = root+1,j=End;
if(flag == 0)
{
while(i<=End && p[root] > p[i]) i++; ///左子树范围
while(j>root && p[root] <= p[j]) j--; ///右子树范围 不能写 j>=root 因为root是根 不用比较
}
else ///镜像二叉树
{
while(i<=End && p[root] <= p[i]) i++; ///左子树范围
while(j>root && p[root] > p[j]) j--; ///右子树范围
}
if(i-1 != j) ///没有一分为二 ij位置见下描述
{
return ;
}
check(root+1,j); ///递归左子树 j的实际位置是在做右子树分界线的左一个
check(i,End); ///递归右子树 i---右一个
last.push_back(p[root]); ///最后把根压进来
}
int main()
{
int n,i,x;
while(cin>>n)
{
flag = 0;
last.clear();
p.clear();
for(i=0; i<n; i++)
{
cin>>x;
p.push_back(x);
}
check(0,n-1);
if(last.size()!=n)
{
last.clear();
flag = 1;
check(0,n-1);
}
if(last.size() == n)
{
cout<<"YES\n";
for(i=0; i<=n-2; i++)
{
cout<<last[i]<<" ";
}
cout<<last[n-1]<<endl;
}
else cout<<"NO\n";
}
return 0;
}