给定K给测试用例,每个测试用例给定一个N个结点的二叉搜索树的前序序列,要求判断该二叉树是不是红黑树。算法
首先使用isRed记录全部的红色结点,这样在建树的时候就能够使用正数来建树。而后再根据先序序列创建二叉搜索树(不须要中序),而后再使用先序遍历判断该数是不是红黑树便可。数组
每一次递归访问首先创建根节点并初始化数据,而后找到第一个大于根节点的位置k,这样[preL+1,k-1]为左子树 ,[k,preR]为右子树,分别递归建树就好。测试
Node* createTree(int preL,int preR){ if(preL>preR) return nullptr; Node *root = new Node; root->data = pre[preL]; // 找到第一个大于根节点的位置k int k; for(k=preL+1;k<=preR;++k){ if(pre[k]>root->data) break; } // [preL+1,k-1]为左子树 root->left = createTree(preL+1,k-1); // [k,preR]为右子树 root->right = createTree(k,preR); return root; }
若是root==nullptr,说明到达叶子结点,将当前路径黑色结点数目countBlack添加进set cntBlack中,而后判断集合大小是否为1,若是不是说明不是红黑树。若是不是叶子结点,就访问该结点,若是是黑色结点,就自增countBlack,若是是红色结点,就判断其存在的孩子是否也是红色结点,若是是就说明不是红黑树,并返回,不然就递归访问左子树和右子树。spa
unordered_set<int> cntBlack;// 记录每一条路径的黑色结点个数 void DFS(Node *root,int countBlack,bool &flag){ if(root==nullptr){ // 到达叶子结点 cntBlack.insert(countBlack); if(cntBlack.size()!=1){ // 出现不一样路径黑色结点不一样的状况 flag = false; } return; } // 当前结点为黑结点 if(!isRed[root->data]){ ++countBlack; }else { // 当前结点为红结点 if((root->left!=nullptr&&isRed[root->left->data])||(root->right!=nullptr&&isRed[root->right->data])) { // 孩子结点也为红色 flag = false; return; } } DFS(root->left,countBlack,flag); DFS(root->right,countBlack,flag); }
在建树以前,先判断根节点是不是黑色结点,若是是再建树,能够减小时间成本。code
#include<cstdio> #include<vector> #include<cstring> #include<unordered_set> using namespace std; struct Node{ int data; Node *left; Node *right; }; const int maxn = 3225;// 通过测试,最小为3225,不然测试点3段错误 bool isRed[maxn];// 记录结点是不是红色的 int pre[maxn];// 前驱序列 unordered_set<int> cntBlack;// 记录每一条路径的黑色结点个数 Node* createTree(int preL,int preR){ if(preL>preR) return nullptr; Node *root = new Node; root->data = pre[preL]; // 找到第一个大于根节点的位置k int k; for(k=preL+1;k<=preR;++k){ if(pre[k]>root->data) break; } // [preL+1,k-1]为左子树 root->left = createTree(preL+1,k-1); // [k,preR]为右子树 root->right = createTree(k,preR); return root; } void DFS(Node *root,int countBlack,bool &flag){ if(root==nullptr){ // 到达叶子结点 cntBlack.insert(countBlack); if(cntBlack.size()!=1){ // 出现不一样路径黑色结点不一样的状况 flag = false; } return; } // 当前结点为黑结点 if(!isRed[root->data]){ ++countBlack; }else { // 当前结点为红结点 if((root->left!=nullptr&&isRed[root->left->data])||(root->right!=nullptr&&isRed[root->right->data])) { // 孩子结点也为红色 flag = false; return; } } DFS(root->left,countBlack,flag); DFS(root->right,countBlack,flag); } int main(){ int K,N; scanf("%d",&K); for(int i=0;i<K;++i){ memset(isRed,0,sizeof(isRed)); cntBlack.clear(); scanf("%d",&N); bool isRedBlackTree = true; for(int j=0;j<N;++j){ scanf("%d",&pre[j]); if(pre[j]<0){ pre[j] = -pre[j]; isRed[pre[j]] = true; } } // 根节点是红色结点必定不是红黑树 if(isRed[pre[0]]) { isRedBlackTree = false; printf("No\n"); }else{ // 根据前序遍历构建二叉搜索树 Node *root = createTree(0,N-1); // 先序遍历判断当前树是不是红黑树 DFS(root,0,isRedBlackTree); if(isRedBlackTree){ printf("Yes\n"); }else{ printf("No\n"); } } } return 0; }