PAT1135 Is It A Red-Black Tree

在这里插入图片描述
题目大意:
题中给了红黑树定义,测试样例中给定树的先序遍历序列,其中负数代表红色节点,要判断该数是否是红黑树。
思路:
通过先序遍历可以得到对应的树,但如何通过这个先序遍历序列判断它是否是一个红黑树呢?

  • 如果一个红色结点的儿子节点有出现不是黑色的,则直接返回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:

  • 一定要看好题目中的每个条件,确保它们都有在代码里体现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值