目录
1,题目描述
Sample Input:
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
Sample Output:
Yes
No
No
题目大意
判断一棵树是否为红黑树。为了简便,题目中正数为黑色节点,负数代表红色节点,值的相对大小通过绝对值比较。
红黑树满足的性质:
- (1) Every node is either red or black.:节点非黑即红;
- (2) The root is black.:根节点为黑色(根节点大于0);
- (3) Every leaf (NULL) is black.:规定空节点(NULL)为黑色;
- (4) If a node is red, then both its children are black.:当一个节点为红色时,其所有孩子节点为黑色;
- (5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.:对每个结点,从该节点向下延申到每个叶子节点的路径中,所有路径含有的黑色节点数目相同;
知识补充
这篇文章讲解的很详细@hucongWh【红黑树】;
这篇文章介绍实例,动态构建红黑树,挺有意思@日拱一兵【红黑树,超强动静图详解,简单易懂】
2,思路
(解决这道题不需要对红黑树有很深刻的认识,只需要判断是否符合性质即可)
用到先序加中序遍历构建二叉树,具体操作可以参考这里@&再见萤火虫&【PAT_甲级_1020 Tree Traversals (25分) (C++)【树的遍历】】
数据结构
- struct node{
int key;
node *left = NULL, *right = NULL;
};动态二叉链表存储节点; - int pre[35], in[35]:先序遍历序列,中序遍历序列(即数组从小到大排序);
- unordered_set<int> record:记录节点到所有叶节点路径中,黑色节点的数目,若record.size()==1则该节点符合条件5,否则说明黑色节点数目不唯一;
算法
- 获得二叉树的先序和中序(由于是balanced binary search tree,所以中序遍历即从小到大的排序)遍历;
- 根据先序和中序遍历,构建二叉树:
- 设计函数getBlackNum,并利用unordered_set<int> record记录节点到所有叶节点路径中,黑色节点的数目,若record.size()==1则该节点符合条件5,否则说明黑色节点数目不唯一;
- 利用DFS遍历二叉树。对每个节点调用函数getBlackNum判断是否满足性质5;当节点为红色时判断其子节点是否满足性质4。利用全局变量flag记录目前为止是否符合红黑树性质,是则继续,不是则返回;
3,AC代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int key;
node *left = NULL, *right = NULL;
};
int pre[35], in[35], K, N, key; //K判断次数 N节点数
bool flag;
unordered_set<int> record; //记录节点到所有叶节点路径中 黑色节点的数目 若record.size()==1则该节点符合条件5
bool cmp1(int a, int b){ return abs(a) < abs(b);}
void buildTree(node *&r, int root, int left, int right){// !!!*&
if(left > right) return;
if(r == NULL){
r = new node();
r->key = pre[root];
}
int i = left;
while(i <= right && in[i] != pre[root])
i++;
buildTree(r->left, root+1, left, i-1);
buildTree(r->right, root+(i-left)+1, i+1, right);
}
void getBlackNum(node *n, int num){
if(n == NULL || n->key > 0) //黑色节点
num++;
if(n == NULL){
record.insert(num);
return;
}
getBlackNum(n->left, num);
getBlackNum(n->right, num);
}
void dfsJudge(node *tree){
if(tree != NULL && flag == true){
record.clear();
getBlackNum(tree, 0);
if(record.size() > 1) flag = false; //判断该节点对应的条件5
if(flag == true && tree->key < 0){ //判断红色节点是否满足条件4
if(tree->left != NULL && tree->left->key < 0)
flag = false;
if(tree->right != NULL && tree->right->key < 0)
flag = false;
}
if(flag == true)
dfsJudge(tree->left);
if(flag == true)
dfsJudge(tree->right);
}
else return;
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
cin>>K;
for(int i = 0; i < K; i++){
flag = true;
scanf("%d", &N);
for(int j = 0; j < N; j++){
scanf("%d", &pre[j]);
if(pre[j] == 0) flag = false;
}
if(pre[0] <= 0)
flag = false;
else{
memcpy(in, pre, N*sizeof(int)); //pre数组拷贝到in数组中
sort(in, in + N, cmp1); // !!!不是sort(pre, pre + N, cmp1);
node *root = NULL;
buildTree(root, 0, 0, N-1);
dfsJudge(root);
}
printf("%s\n", flag ? "Yes":"No");
}
return 0;
}
4,解题过程
一发入魂o(* ̄▽ ̄*)ブ