|
题目大意
给一棵二叉搜索树的前序遍历,判断它是否为红黑树,是输出Yes,否则输出No。思路解析
第一眼看到红黑树着实吓了一跳,暗想陈姥姥真狠……但是题意倒不难,一遍就AC了。本题比较纠结的是第3条注解,是在不理解什么意思,于是直接把它忽略了,事实证明没有任何影响。所以本题所用到的红黑树判定条件是这样的:
1. 根节点是黑的;
2. 红节点的孩子都是黑的;
3. 对于任意一个节点,从它遍历到它的所有叶子子孙所经历的黑节点个数是相等的。
前两点都好判断,第三点仔细想一想:树又不是图,树只有一个入度,只要保证根节点到所有叶子节点所经历的黑节点个数都相等不就满足了吗,所以一遍DFS就可以判断出来。
示例代码
#include<iostream>
#include<map>
#include<set>
using namespace std;
struct node{
public:
int val;
struct node* left, *right;
};
map<int, int> mapp;//value为1说明是红树
node* build(node* tree, int val) {
if (tree == NULL) {
tree = new node();
tree->val = val;
return tree;
}
if (val < tree->val) tree->left = build(tree->left, val);
if (val > tree->val) tree->right = build(tree->right, val);
return tree;
}
bool isover;
bool judge1(node* tree, int pre) {//检测节点是红的,它的两个孩子都是黑的 pre为1表示当前节点的父节点是红的
if (tree == NULL || !isover) return true;
if (pre == 1) {
if ((tree->left != NULL && mapp[tree->val] == 1)) {
isover = false;
return false;
}
}
if(isover)
judge1(tree->left, mapp[tree->val]);
if(isover)
judge1(tree->right, mapp[tree->val]);
return isover;
}
set<int> se;//存放所有从根到叶子节点的路径所经历的黑节点个数
void judge2(node* tree,int count) {
if (tree == NULL) {//遍历到了叶子节点
se.insert(count);
return;
}
if (mapp[tree->val] == 0) {
judge2(tree->left, count + 1);
judge2(tree->right, count + 1);
}
else {
judge2(tree->left, count);
judge2(tree->right, count);
}
}
int main() {
int n, m, val;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &m);
mapp.clear();
se.clear();
node* tree = NULL;
isover = true;
for (int j = 0; j < m; j++) {
scanf("%d", &val);
val < 0 ? mapp[abs(val)] = 1 : mapp[val] = 0;
tree = build(tree, abs(val));
}
bool flag = true;
if (mapp[tree->val] == 1 || !judge1(tree, 0)) flag = false;
if (flag) judge2(tree, 0);
if (se.size() > 1 || !flag)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}