题目翻译:
先给出了红黑树的定义,而后让你去判断一个给定的二叉搜索树的前序序列,这个二叉搜索树是否是红黑树。
题解思路:
首先明确什么是红黑树?
数据结构中有一类平衡的二叉搜索树,称为红黑树。
它具有以下 5 个属性:
1.节点是红色或黑色。
2.根节点是黑色。
3.所有叶子都是黑色。(叶子是 NULL节点)(注意这个不是我们寻常认为的叶子结点)
4.每个红色节点的两个子节点都是黑色。
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
可以选择建树或者不建树。
建树的话:
将二叉搜索树的前序排序后就是中序,由中序和前序就可以建树了;或者直接由BST插入建树。
建树之后就用dfs的思想对树进行性质2、4、5的判定即可,对于性质5,只需要判断任意一条从根结点到每一个叶子结点的路径上黑色结点的数量相同就行了。
不建树的话:
只需要去记录几个变量再配合使用前序和中序序列便能遍历整棵树了。
代码:
建树:
#include<bits/stdc++.h>
using namespace std;
const int N = 31;
pair<int, bool> pre[N];
int K, t_max = 0, tag = 0;//t_max=0表示还未求得第一个从根结点到任意一个叶结点路上黑色结点的数量,tag=1表示已经判断为No
struct node {
bool c;//0为红,1为黑
int val = 0, l = -1, r = -1;
};
vector<node> v(N);
int ind = 0;//下标从0开始
void build(int& root, int h)//静态建树
{
if (root == -1)
{
root = ind++;
v[root].val = abs(h);
v[root].c = (h >= 0) ? 1 : 0;
}
else if (abs(h) < v[root].val)
build(v[root].l, h);
else if (abs(h) > v[root].val)
build(v[root].r, h);
}
void isRB(int cur, int num)
{
if (tag == 1 || cur == -1) return;
if (v[cur].c) num++;
else
{
if ((!v[v[cur].l].c && v[cur].l != -1) || (!v[v[cur].r].c && v[cur].r != -1))//如果不满足红色结点的孩子结点为黑色
{
tag = 1;
cout << "No" << endl;
return;
}
}
if ((v[cur].l == -1 || v[cur].r == -1) && !tag)//注意这里是或,而不是与
{
if (!t_max) {
t_max = num;
}
else
{
if (num != t_max)//如果不满足从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
{
tag = 1;
cout << "No" << endl;
return;
}
}
}
isRB(v[cur].l, num);
isRB(v[cur].r, num);
}
int main()
{
cin >> K;
while (K--)
{
vector<node> v1(N);
v = v1;
t_max = 0, tag = 0;ind = 0;
int t, root = -1;cin >> t;
for (int i = 0;i < t;i++)
{
int p;cin >> p;
build(root, p);
if (p >= 0)
pre[i] = make_pair(p, 1);
else
pre[i] = make_pair(-1 * p, 0);
}
if (v[root].c)
{
isRB(root, 0);
if (!tag)
cout << "Yes" << endl;
}
else
cout << "No" << endl;
}
}
不建树:
#include<bits/stdc++.h>
using namespace std;
int blackNum = -1, flag = -1;
unordered_map<int, int> indice;
struct node{
int num;
bool isRed;
bool operator < (const node& p){
return num < p.num;
}
};
void getAns(vector<node>& pre, vector<node>& in, int pivot, int inl, int inr, bool isFatherRed, int black){
if(inl > inr){//如果当前已到达叶子节点
if(black + 1 != blackNum && blackNum != -1)//条件5:每条路径上的黑节点数相等
flag = 1;
else
blackNum = black + 1;
return;
}
if(pre[pivot].isRed && isFatherRed){//条件4:红父节点的孩子必为黑,通过设置入口参数使得条件2的判断也在此进行
flag = 1;
return;
}
int pos = indice[pre[pivot].num];//下面就是相当于一个前序遍历,或者说是DFS
getAns(pre, in, pivot + 1, inl, pos - 1, pre[pivot].isRed, pre[pivot].isRed ? black : black + 1);
getAns(pre, in, pivot + pos - inl + 1, pos + 1, inr, pre[pivot].isRed, pre[pivot].isRed ? black : black + 1);
}
int main(){
int k, n, u;
cin >> k;
while(k--){
cin >> n;
vector<node> pre(n);
for (int i = 0; i < n;i++){
cin >> u;
pre[i].num = abs(u);
pre[i].isRed = u < 0 ? true : false;
}
vector<node> in(pre);
sort(in.begin(), in.end());
for (int i = 0; i < n;i++)
indice[in[i].num] = i;
blackNum = flag = -1;//切记初始化啊,不然就错了。。。。。哭聊
getAns(pre, in, 0, 0, n - 1, true, 0);
if(flag == 1) cout << "No" << endl;
else cout << "Yes" << endl;
}
return 0;
}
坑点:
对于测试点2和3的错误,请再仔细阅读红黑树的判断性质3和5。
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.
这个性质一定要搜索到NULL 节点再来判断。否则就有可能出现你认为是红黑树,但它不是红黑树
如:
还有就是红黑树不允许插入相同的值,本题的样例也没考虑这一个,所以如果你测试点错了,不用考虑这个问题。