PAT-ADVANCED1135——Is It A Red-Black Tree

我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED

原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805346063728640

题目描述:

题目翻译:

1135 这是一棵红黑树吗

在数据结构中有一种称为红黑树的平衡二叉搜索树。 它有以下5个属性:

(1)每个节点都是红色或黑色。
(2)根是黑色的。
(3)每个叶子(NULL)都是黑色的。
(4)如果一个节点是红色的,那么它的两个孩子都是黑色的。
(5)对于每个节点,从节点到后代叶子的所有简单路径包含相同数量的黑色节点。

例如,图1中的树是红黑树,而图2和3中的树则不是。

对于每个给定的二叉搜索树,你需要指出它是否是合法的红黑树。

输入格式:

每个输入文件包含几个测试用例。第一行给出正整数K(<= 30),即测试用例总数。对于每种情况,第一行给出正整数N(<= 30),即二叉树中的节点总数。第二行给出树的前序遍历序列。虽然树中的所有键都是正整数,但我们使用负号来表示红色节点。一行中的所有数字都用空格分隔。样例输入对应于图1,2和3中所示的树。

输出格式:

对每个测试用例,如果该树是一棵红黑树,则打印“Yes”,否则打印“No”。

输入样例:

3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17

输出样例:

Yes
No
No

知识点:根据前序遍历重建二分搜索树、树的深度优先遍历

思路:先根据前序遍历重建二分搜索树,再深度优先遍历判断其是否是一棵红黑树

重建二分搜索树时,我们比较的应该是其绝对值,因为负号仅代表该节点是红色,不代表节点大小。来看红黑树的5个条件:

(1)条件1,题目自动满足。

(2)条件2,直接判断所建树的根结点是否是正数即可。

(3)条件3,无需判断。

(4)条件4,dfs过程中一旦出现了红节点(即负数节点),如果其有左孩子或右孩子,判断其是否是黑色即可。

(5)条件5,dfs记录到叶子节点的每条路径,递归终止时,判断路径上负数节点的个数,将个数存入set集合countBlack中,利用set集合的去重特性来判断树中每个节点到叶子所经过的黑色节点数是否相等。如果最后countBlack中只有一个元素,说明每个节点到叶子所经过的黑色节点数均相等,满足该条件,否则不满足该条件。

C++代码:

#include<iostream>
#include<vector>
#include<set>
#include<cmath>

using namespace std;

struct node {
	int data;
	node* lchild;
	node* rchild;
};

set<int> countBlack;
vector<int> tempPath;

node* create(vector<int> levelOrder);
void dfs(node* nowVisit, bool &flag);
bool isRBTree(node* head);

int main() {
	int K;
	scanf("%d", &K);
	for(int i = 0; i < K; i++) {
		int N;
		scanf("%d", &N);
		vector<int> levelOrder;
		int num;
		for(int j = 0; j < N; j++) {
			scanf("%d", &num);
			levelOrder.push_back(num);
		}
		node* head = create(levelOrder);
		if(isRBTree(head)) {
			printf("Yes\n");
		} else {
			printf("No\n");
		}
	}
	return 0;
}

node* create(vector<int> levelOrder) {
	if(levelOrder.size() <= 0) {
		return NULL;
	}
	node* head = new node();
	head->data = levelOrder[0];
	vector<int> left;
	vector<int> right;
	for(int i = 1; i < levelOrder.size(); i++) {
		if(abs(levelOrder[i]) < abs(levelOrder[0])) {
			left.push_back(levelOrder[i]);
		} else {
			right.push_back(levelOrder[i]);
		}
	}
	head->lchild = create(left);
	head->rchild = create(right);
	return head;
}

void dfs(node* nowVisit, bool &flag) {
	if(nowVisit == NULL) {
		int count = 0;
		for(int i = 0; i < tempPath.size(); i++) {
			if(tempPath[i] > 0) {
				count++;
			}
		}
		countBlack.insert(count);
		return;
	}
	if(nowVisit->data < 0) {
		if(nowVisit->lchild != NULL) {
			if(nowVisit->lchild->data < 0) {
				flag = false;
			}
		}
		if(nowVisit->rchild != NULL) {
			if(nowVisit->rchild->data < 0) {
				flag = false;
			}
		}
	}
	tempPath.push_back(nowVisit->data);
	dfs(nowVisit->lchild, flag);
	dfs(nowVisit->rchild, flag);
	tempPath.pop_back();
}

bool isRBTree(node* head) {
	if(head->data < 0) {
		return false;
	}
	bool flag = true;
	countBlack.clear();
	tempPath.clear();
	dfs(head, flag);
	if(countBlack.size() != 1 || !flag) {
		return false;
	}
	return true;
}

C++解题报告:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值