题目大意:
题中给了红黑树定义,测试样例中给定树的先序遍历序列,其中负数代表红色节点,要判断该数是否是红黑树。
思路:
通过先序遍历可以得到对应的树,但如何通过这个先序遍历序列判断它是否是一个红黑树呢?
- 如果一个红色结点的儿子节点有出现不是黑色的,则直接返回No;
是否可以在遍历的过程中分别设定左右子树的黑色节点个数,若出现有一环节的数目不一致,则把判断变量改成false,输出No
代码:
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> v;
bool flag;
int pretraverse(int preL,int preR){
//cout<<v[preL]<<":"<<endl;
if(preL>preR) return 0;
int root=v[preL];int lrooti=preL+1;int rrooti=preL+1;
for(;rrooti<=preR;rrooti++){
if(abs(v[rrooti])>abs(root)) break;
}
int lbn=0,rbn=0;
if(lrooti<=preR){
if(v[lrooti]>0) lbn=pretraverse(lrooti,rrooti-1)+1;
else{
if(root<0) flag=0;
lbn=pretraverse(lrooti,rrooti-1);
}
}
if(rrooti<=preR){
if(v[rrooti]>0) rbn=pretraverse(rrooti,preR)+1;
else{
if(root<0) flag=0;
rbn=pretraverse(rrooti,preR);
}
}
if(lbn==rbn) return lbn;
else{
flag=false;
return min(lbn,rbn);
}
}
int main(){
int k;
cin>>k;
while(k--){
int n;
cin>>n;
v.clear();
v.resize(n+1);
for(int i=1;i<=n;i++) cin>>v[i];
flag=true;
int num=pretraverse(1,n);
if(flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}
但有一个样例没有通过,暂时还在想原因。
后来想想应该是在这段代码这里出了问题:
if(lbn==rbn) return lbn;
else{
flag=false;
return min(lbn,rbn);
}
由于不相等的时候返回的值的不确定性,可能会造成一定程度上本应该判断为错误的红黑树被误判成了正确。而这个地方造成的原因是整个算法本身思想的缺陷。
看了一下其他的代码,思想为:根据前序遍历序列用链表建树,通过建立的树用两个判断条件(判断左右子树是否黑色节点一致,判断父节点为红时子节点是否为红)进行遍历并返回结果。
好的,最后我依照这个思想实现了一遍,但发现它在一个节点的子代黑色节点数目的判断上也是采取max(l,r)
的方法,我将其改成了min(l,r)
好像也不影响最后答案的正确。但是在最后我发现了为什么第二个测试案例出错:
因为没有判断根节点是否大于0,若小于0,就不是红黑树。
所以我在原先代码处加了一个v[1]>0
,通过了。
修正后代码:
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> v;
bool flag;
int pretraverse(int preL,int preR){
if(preL>preR) return 0;
int root=v[preL];int lrooti=preL+1;int rrooti=preL+1;
for(;rrooti<=preR;rrooti++){
if(abs(v[rrooti])>abs(root)) break;
}
int lbn=0,rbn=0;
if(lrooti<=preR){
if(v[lrooti]>0) lbn=pretraverse(lrooti,rrooti-1)+1;
else{
if(root<0) flag=0;
lbn=pretraverse(lrooti,rrooti-1);
}
}
if(rrooti<=preR){
if(v[rrooti]>0) rbn=pretraverse(rrooti,preR)+1;
else{
if(root<0) flag=0;
rbn=pretraverse(rrooti,preR);
}
}
if(lbn==rbn) return lbn;
else{
flag=false;
return min(lbn,rbn);
}
}
int main(){
int k;
cin>>k;
while(k--){
int n;
cin>>n;
v.clear();
v.resize(n+1);
for(int i=1;i<=n;i++) cin>>v[i];
flag=true;
int num=pretraverse(1,n);
if(flag&&v[1]>0) printf("Yes\n");
else printf("No\n");
}
return 0;
}
tips:
- 一定要看好题目中的每个条件,确保它们都有在代码里体现。