PAT_甲級_1143 Lowest Common Ancestor

題目大意:

給定一顆二叉排序樹的先序序列,輸出待查詢的兩個節點的最近公共祖先 。node

算法思路1(不建樹):

使用$pre$存放輸入的先序序列,$isLegal$標記每個樹中的節點,對於輸入的節點只要小於0或者$isLegal$對應值爲false,就說明不在樹中,輸出對應的$ERROR$信息,都在就在先序序列中進行搜索,假設輸入的結點爲$a$和$b$,那麼對應$a$和$b$的全部祖先必定是在先序序列中從左向右依次排列,那麼第一次在先序序列中出現的祖先就是$a$和$b$的最近公共祖先,對於$a$和$b$的祖先,必定是在$a$和$b$之間,也就是處在$[a,b]$或者$[b,a]$之中,因此,咱們須要作的事情就是遍歷一遍pre數組,找到第一個處於$[a,b]$或者$[b,a]$之間的結點$ans$,而後進行輸出便可。ios

算法思路2(建樹):

首先根據二叉查找樹的前序序列構建二叉排序樹 ,對創建好的二叉查找樹進行層序遍歷,初始化每一個結點的層次和父節點,首先對於2個層次不一樣的結點A和B,layer=max(Alayer,Blayer),則祖先必定不在layer層上,那麼先檢查min(Alayer,Blayer) 層上的結點是不是另一個結點的祖先,也就是隻要 Alayer!=Blayer,層數較大者一直往上走,若是層數相等後剛好爲其中一個結點,則該結點就是最小公共祖先,不然2個結點同時向上走,知道走到同一結點或者到NULL。算法

注意點:

  • 一、結點的數值能夠大於100000,因此isLegal數組大小最小爲193313,不然測試點2會出現段錯誤。

提交結果:

image.png

AC代碼1:

#include<cstdio>

using namespace std;

struct Node{
    int data;
    Node *left;
    Node *right;
};

int pre[100005];// 先序序列
bool isLegal[193313];// 標記樹中的每個結點,太小會致使測試點2段錯誤 

int main(){
    int M,N;// 查詢數目和結點數目 
    scanf("%d %d",&M,&N);
    for(int i=0;i<N;++i){
        scanf("%d",&pre[i]);
        isLegal[pre[i]] = true;
    }
    int a,b;
    for(int i=0;i<M;++i){
        scanf("%d %d",&a,&b);
        bool not_legal_a = a<0?true:!isLegal[a];
        bool not_legal_b = b<0?true:!isLegal[b];
        if(not_legal_a&&not_legal_b){
            printf("ERROR: %d and %d are not found.\n",a,b);
        }else if(not_legal_a){
            printf("ERROR: %d is not found.\n",a);
        }else if(not_legal_b){
            printf("ERROR: %d is not found.\n",b);
        }else{
            // a和b都在樹中
            int ans;
            for(int i=0;i<N;++i){
                if((pre[i]>=a&&pre[i]<=b)||(pre[i]>=b&&pre[i]<=a)){
                    ans = pre[i];
                    break;
                }
            } 
            if(ans==a){
                // a是b的祖先 
                printf("%d is an ancestor of %d.\n",ans,b); 
            }else if(ans==b){
                // b是a的祖先
                printf("%d is an ancestor of %d.\n",ans,a);
            }else {
                printf("LCA of %d and %d is %d.\n",a,b,ans); 
            }
        }
    }
    return 0;
}

AC代碼2:

#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];
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){
    if(preL>preR){//當前子樹爲空,沒有結點 
        return NULL;
    }
    node* root = newNode(pre[preL]);
    //首先找到第一個大於當前子樹根結點的位置i
    int i;
    for(i=preL+1;i<=preR;++i){
        if(root->data<pre[i]){
            break;
        }
    } 
    //往左子樹插入,左子樹範圍爲[preL+1,k-1] 
    root->lchild = create(preL+1,i-1);
    //往右子樹插入,右子樹範圍爲[k,preR]
    root->rchild = create(i,preR);
    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",&pre[i]);
        Hash[pre[i]] = i+1;
    }
    node* root = create(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;
}
相關文章
相關標籤/搜索