爆刷PAT(甲級)——之【1151】 LCA in a Binary Tree (30 分)——先序中序建樹+LCA問題

此題也是去年考的時候不會。時隔一年纔來補一下。

這題網上其實很多的講解了。大概分成三種講法流派,一種是以柳神爲代表的非建樹遞歸找父子關係派;一類是最通俗常規的建樹+遍歷遞歸找LCA方法派;還有一類是隻貼代碼沒有講解或是使用了RMQ倍增高級方法解決LCA問題等。

記此博客來簡單的縷一縷自己的LCA思緒。

腦袋已經鏽了很久了。

 

1、先談一下,最常規的建樹+遞歸遍歷LCA方法,本題複雜度就是O(2MN+MN):

題意;給一個二叉樹(並不是BST)的先序遍歷和中序遍歷,節點值不重複。然後給M個值對的查詢,求它們的最近公共祖先LCA節點。

難點:一個數輸出的時候要分成好幾個情況,寫起來比較蛋疼。

還有一個,先不談是不是必要進行建樹,我們姑且就要建樹的話,如何寫出先序遍歷/後序遍歷 + 中序遍歷進行建樹。這個不去看一下以及多寫幾遍,是會導致大悲劇的。很重要!

第三個是,在判斷完畢待查校訓數據是否存在有效之後,如何進行常規的LCA遞歸遍歷二叉樹去尋找最近共同祖先呢?思路是——LCA的共同祖先分成三種情況:A和B不在同一顆子樹,那麼A和B的共同“根爺爺”就是答案;A在B的下側,那麼B就是A的祖先(在一側);反之亦然,B在A的下側(同側),那麼A就是B的祖先。——如此以來,我們從根節點開始遞歸左子樹以及右子樹分別去找A或者B,如果先找到了A,那不就說明B在A的下面幾層(所以才A找到的時候B還沒找到);如果先找到了B而A沒找到,那A就是祖先;如果在左右子樹分別找到A和B,那就說明當前節點就是它們的“共同根祖先”。

 

詳細看代碼吧

Code:

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define inf 10009
#define INF 0x3f3f3f3f
int n,m;
int preorder[inf],inorder[inf];
struct Node
{
    Node *left,*right;
    int value;
    Node(int v)
    {
        value=v;
        left=right=NULL;
    }
};
int flag;//結果類型
Node* Preorder_Inorder_Create(int l1,int r1,int l2,int r2)//先序中序遍歷建樹
{
    if(l2>r2)return NULL;
    Node *root=new Node(preorder[l1]);
    int i;
    for(i=l2;inorder[i]!=preorder[l1];i++);
    int len=i-l2;
    root->left=Preorder_Inorder_Create(l1+1,l1+len,l2,i-1);
    root->right=Preorder_Inorder_Create(l1+1+len,r1,i+1,r2);
    return root;
}
Node* findFather(Node *root,int a,int b)//遞歸找公共祖先
{
    if(!root)return NULL;
    else if(root->value==a||root->value==b)return root;

    Node *left=findFather(root->left,a,b);
    Node *right=findFather(root->right,a,b);
    if(left&&right){return root;}//左右子樹
    else if(!left)return right;//在一邊——右邊
    else return left;//在一邊——左邊
}
int main()
{
    int i,j,k;
    cin>>m>>n;
    for(i=0;i<n;i++)cin>>inorder[i];
    for(i=0;i<n;i++)cin>>preorder[i];
    Node *root=Preorder_Inorder_Create(0,n-1,0,n-1);
    while(m--)
    {
        int a,b;
        cin>>a>>b;

        //判斷數是否存在
        for(i=0;i<n;i++)if(preorder[i]==a)break;
        for(j=0;j<n;j++)if(preorder[j]==b)break;
        bool exsit1=(i==n)?1:0;
        bool exsit2=(j==n)?1:0;
        if(exsit1&&exsit2){printf("ERROR: %d and %d are not found.\n",a,b);continue;}//都不在
        else if(exsit1||exsit2){printf("ERROR: %d is not found.\n",exsit1?a:b);continue;}//某一個不在

        Node *ans=findFather(root,a,b);
        int value=ans->value;
        if(value==a)printf("%d is an ancestor of %d.\n",a,b);
        else if(value==b)printf("%d is an ancestor of %d.\n",b,a);
        else printf("LCA of %d and %d is %d.\n",a,b,value);
    }

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章