PAT A1135 Is It A Red-Black Tree
通过此题才了解了红黑树,之前由于这个名字太唬人了一直没敢看——原来这货的平衡性比AVL要弱,目的仿佛是为了减少旋转的开销?以比较小的代价实现较高查找效率。(ps:然而又旋转又变色更吓人,业原火?) 本次的任务是检查三个性质:根节点为黑,直接看;路径上不能有连续的两个红,可以在建树的参数中传个color,上下一比较就知道了;任一节点到其叶节点的所有路径中,黑的数量要相等(因为红不能连续,而黑要数量相等,所以可以保证长路径不会大于短路径的2倍) 所以思路就是先序中序建树(BST的中序是有序序列),传参color用于比较两红的情况,通过递归统计路径上黑的数量。(ps:flag==false时的return只是为了节省时间,没有数量意义) 这里我最开始理解成根节点到叶子的所有路径要有相同数量的黑,所以传了个cnt下去累加,只过了前两个测试点;弄明白之后觉得反正不需要节点之间的关系,就把返回值改成了子路径上的黑个数,每个人根据下层的反馈进行判断,并加上自身的情况报告给上层 建树的过程既可以向下传参,又可以递归得到下面的情况,不愿意传的数据还可以扔到节点里保存和调整 ——所以相关的问题都可以类似解决 看网上的解法可以用先序直接插入建树,道理上好像是正确的,只是之前仿佛没人教过,get;
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector< int > preorder, inorder;
bool cmp ( int n1, int n2) {
return abs ( n1) < abs ( n2) ;
}
bool flag = true ;
int build ( int root, int inL, int inR, int color) {
if ( ! flag || inL > inR) return 0 ;
int pos = inL;
while ( inorder[ pos] != preorder[ root] ) pos ++ ;
if ( color < 0 && inorder[ pos] < 0 ) {
flag = false ;
return - 1 ;
}
int leftcnt = build ( root + 1 , inL, pos - 1 , inorder[ pos] ) ;
int rightcnt = build ( root + 1 + pos - inL, pos + 1 , inR, inorder[ pos] ) ;
if ( leftcnt != rightcnt) {
flag = false ;
return - 1 ;
}
return leftcnt + ( inorder[ pos] > 0 ) ;
}
int main ( ) {
int M, N;
cin >> M;
for ( int i = 0 ; i < M; i ++ ) {
cin >> N;
preorder. resize ( N) ;
inorder. resize ( N) ;
flag = true ;
for ( int j = 0 ; j < N; j ++ ) {
cin >> preorder[ j] ;
inorder[ j] = preorder[ j] ;
}
if ( preorder[ 0 ] < 0 ) {
cout << "No\n" ;
continue ;
}
sort ( inorder. begin ( ) , inorder. end ( ) , cmp) ;
build ( 0 , 0 , N - 1 , 1 ) ;
if ( ! flag) cout << "No\n" ;
else cout << "Yes\n" ;
}
return 0 ;
}