给定一颗含有N个节点的前序和中序序列,要求给定任意2个节点,须要输出其最近公共祖先。node
这里和1143同样给出2种思路,一种不用建树,一种须要建树。ios
咱们借鉴建树的递归过程完成树的部分搜索,若是当前搜索的子树的根节点和查询节点U和V相等,说明其中之一就是祖先,直接保存并返回便可,不然获取U和V是否在左子树或者右子树的标志,若是都在左子树,那么就都往左子树搜索,若是都在右子树,那么就都往右子树搜索,不然说明当前子树的根节点就是U和V的最近公共祖先,直接保存并返回便可,具体作法就是,在输入中序序列的时候,使用pos保存每个节点在中序遍历序列中的位置,那么每一次递归查找中序序列根节点的位置就能够替换为int k = pos[pre[preL]];
而后再使用uInRight和vInRight分别表示U和V是否在右子树,true表示在右子树,获取的方法也很简单,就是pos[U]>k
和pos[V]>k
便可,而后再根据uInRight和vInRight的值,要么递归搜索,要么保存祖先ancestor = pre[preL];
并返回便可。算法
首先根据前序和中序创建一颗二叉树,而后利用层序遍历的方法得到每个节点的父亲和其所在层数,对于输入的节点x和y,若是节点所在层数同样,那么只要二者不相等就一同向上搜索,直到相遇,其相遇节点即为最近公共祖先,不然让层数更大的那个先向上走,直到和另一个节点层数相同,而后再同时向上,直到相遇为止。数组
#include<cstdio> using namespace std; const int maxn = 0x3ffffff; int N,M;// 节点数目和测试数目 int pre[maxn],in[maxn]; bool isValid[maxn]; int pos[maxn];// 每个节点在中序序列中的下标,不会超时的关键 void createTree(int preL,int preR,int inL,int inR,int &ancestor,int U,int V){ if(preL>preR) return; if(pre[preL]==U||pre[preL]==V){ ancestor = pre[preL]==U?U:V; return ; } // 找到根节点在中序序列中的位置 int k = pos[pre[preL]];// 直接获取位置 int numOfLeft = k-inL;// 左子树节点个数 bool uInRight = pos[U]>k,vInRight = pos[V]>k;// U和V在左子树仍是右子树,true在右子树 if(uInRight&&vInRight){ // U和V都在右子树 createTree(preL+numOfLeft+1,preR,k+1,inR,ancestor,U,V); } else if(!uInRight&&!vInRight){ // U和V都在左子树 createTree(preL+1,preL+numOfLeft,inL,k-1,ancestor,U,V); } else { // U和V分别在左右子树 ancestor = pre[preL]; return; } } int main(){ scanf("%d %d",&M,&N); for (int i = 0; i < N; ++i) { scanf("%d",&in[i]); isValid[in[i]] = true; pos[in[i]] = i; } for (int i = 0; i < N; ++i) { scanf("%d",&pre[i]); } for (int j = 0; j < M; ++j) { int u,v; scanf("%d %d",&u,&v); if(!isValid[u]&&!isValid[v]){ printf("ERROR: %d and %d are not found.\n",u,v); } else if(!isValid[u]){ printf("ERROR: %d is not found.\n",u); } else if(!isValid[v]){ printf("ERROR: %d is not found.\n",v); } else { int ancestor = -1; createTree(0,N-1,0,N-1,ancestor,u,v); if (ancestor==u||ancestor==v){ printf("%d is an ancestor of %d.\n",ancestor,ancestor==u?v:u); } else { printf("LCA of %d and %d is %d.\n",u,v,ancestor); } } } return 0; }
#include<cstdio> #include<string> #include<cstring> #include<iostream> #include<queue> #include<algorithm> using namespace std; struct node{ int data; int level; node* lchild; node* rchild; node* parent; }; const int maxn = 200005; int pre[maxn],in[maxn]; int Hash[maxn];//PAT不能用hash node* preN[maxn]; int num = 0;//先序遍历下标 node* newNode(int x){ node* w = new node; w->data =x; w->level = 1; w->lchild=w->rchild=w->parent=NULL; return w; } //根据当前子树的前序排序序列和中序排序序列构建二叉树 node* create(int preL,int preR,int inL,int inR){ if(preL>preR){//当前子树为空,没有结点 return NULL; } node* root = newNode(pre[preL]); //首先找到中序遍历序列中等于当前根结点的值得下标 int i; for(i=inL;i<=inR;++i){ if(in[i]==pre[preL]){ break; } } int numLeft = i-inL; //往左子树插入,左子树先序遍历区间为[preL+1,preL+numleft],中序遍历区间为[inL,i-1] root->lchild = create(preL+1,preL+numLeft,inL,i-1); //往右子树插入,右子树先序遍历区间[preL+numLeft+1,preR],中序遍历区间为[i+1,inR] root->rchild = create(preL+numLeft+1,preR,i+1,inR); return root; } //先序遍历 void tre(node* root){ if(root==NULL) return; preN[num++] = root; tre(root->lchild); tre(root->rchild); } //层序遍历 void layerOrder(node* root){ queue<node*> q; q.push(root); while(!q.empty()){ node* w = q.front(); q.pop(); if(w->lchild!=NULL){ w->lchild->level = w->level+1; w->lchild->parent = w; q.push(w->lchild); } if(w->rchild!=NULL){ w->rchild->level = w->level+1; w->rchild->parent = w; q.push(w->rchild); } } } int main(){ int m,n;//测试的结点对数和结点数目 scanf("%d %d",&m,&n); memset(Hash,0,sizeof(Hash)); for(int i=0;i<n;++i){ scanf("%d",&in[i]); } for(int i=0;i<n;++i){ scanf("%d",&pre[i]); Hash[pre[i]] = i+1; } node* root = create(0,n-1,0,n-1); layerOrder(root); //先序遍历 tre(root); //测试 int x,y; for(int i=0;i<m;++i){ scanf("%d %d",&x,&y); if(Hash[x]!=0&&Hash[y]!=0){ //均是树中结点 node* w1 = preN[Hash[x]-1];//经过结点的值找到前序遍历数组的下标,而后再找到对应结点 node* w2 = preN[Hash[y]-1]; if(w1->level==w2->level){ //2个结点在同一层 if(w1==w2){ printf("%d is an ancestor of %d.\n",x,y); } else{ //2结点不相等,则同时往上走 node* t1 = w1; node* t2 = w2; while(t1->parent!=NULL){ t1 = t1->parent; t2 = t2->parent; if(t1==t2){ printf("LCA of %d and %d is %d.\n",x,y,t1->data); break; } } } }else{ //2结点不在同一层,让层数较大的先往上走 node* max = w1->level>w2->level?w1:w2; node* min = w1->level<w2->level?w1:w2; while(max->level!=min->level&&max->parent!=NULL){ max = max->parent; } //而后判断min是否和max相等 if(min==max){ //说明min是max的祖先,但此时max已经更改因此得从新赋值 max = w1->level>w2->level?w1:w2; printf("%d is an ancestor of %d.\n",min->data,max->data); } else{ //2结点不相等,则同时往上走 while(max->parent!=NULL){ max = max->parent; min = min->parent; if(max==min){ printf("LCA of %d and %d is %d.\n",x,y,min->data); break; } } } } }else if(Hash[x]==0&&Hash[y]!=0){ printf("ERROR: %d is not found.\n",x); }else if(Hash[x]!=0&&Hash[y]==0){ printf("ERROR: %d is not found.\n",y); }else{ printf("ERROR: %d and %d are not found.\n",x,y); } } return 0; }