PAT_甲級_1138 Postorder Traversal (25point(s)) (C++)【樹的遍歷/先序+中序->後序】

目錄

1,題目描述

題目大意

2,思路

3,AC代碼

4,解題過程

第一搏

第二搏

第三搏

第四搏


1,題目描述

Sample Input:

7
1 2 3 4 5 6 7
2 3 1 5 4 7 6

 

Sample Output:

3

題目大意

利用二叉樹的先序和中序遍歷,輸出後序遍歷的第一個節點。

 

2,思路

先序遍歷+中序遍歷=》後序遍歷。

構建過程可以參考@&再見螢火蟲&【PAT_甲級_1020 Tree Traversals (25分) (C++)【樹的遍歷】】

 

這裏只需要輸出後序遍歷的第一個數字,即整棵樹的第一個葉節點

用left和right限定中序遍歷的左右界限,root指定先序遍歷中的首節點(整棵樹的根節點)

只要有左子樹,就不斷縮減右邊界;無左子樹(in[left]==pre[root])且left<right,說明仍未找到葉節點,便增加左邊界,遍歷右子樹尋找第一個葉節點;

當左右邊界重合時,便找到了第一個葉節點!

(注意,在尋找根節點pre[root]在中序遍歷中的位置。以便分割子樹時,可以用map記錄值在中序遍歷(in)中的位置,可以節省很多時間)

 

3,AC代碼

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    unordered_map<int, int> inMap;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++){
        scanf("%d", &in[i]);
        inMap[in[i]] = i;
    }
    int left = 0, right = N-1, root = 0;
    while(left < right){    //left=right時 即爲第一個葉節點
        int i = inMap[pre[root]];
        if(i > left){       //有左子樹
            right = i - 1;
            root++;
        }else{              //無左子樹 且右子樹不爲空
            root += (i - left + 1);
            left = i + 1;
        }
    }
    cout<<in[left];         //left=right 合併爲一個節點
    return 0;
}

4,解題過程

第一搏

???這不是簡化版的先序加中序-》後序嗎

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++)
        scanf("%d", &in[i]);
    bool flag = false;
    int left = 0, right = N-1, root = 0;
    while(left <= right && in[right] != pre[root]){
        int i = left;
        while(i <= right && in[i] != pre[root])
            i++;
        right = i - 1;
        root++;
    }
    cout<<pre[root];
    return 0;
}

第二搏

重新考慮了一下,發現這裏的邏輯有問題:

只考慮了左子樹的情況,沒有想到左子樹爲空的情況,於是改進了一下:

第三搏

這複雜度要是超時,真的沒有算法可以解決了。。。

所以我懷疑是邊界沒處理好,陷入了死循環。。。

最終鎖定這裏【語句順序寫反了!!!】

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++)
        scanf("%d", &in[i]);
    int left = 0, right = N-1, root = 0;

    while(left < right){
        int i = left;
        while(i <= right && in[i] != pre[root])
            i++;
        if(i > left){//有左子樹
            right = i - 1;
            root++;
        }else{
            root += (i - left + 1);
            left = i + 1;
            //root += (i - left + 1); !!!此時left已經改變
        }

    }
    cout<<in[left];
    return 0;
}

622ms。。。

擦槍走火的感覺可太刺激了。。。

第四搏

突然又注意到這裏查找根節點是O(N)的複雜度。。。爲什麼不用map記錄中序遍歷中各節點的位置呢?

於是

高呼666!(o゜▽゜)o☆[BINGO!]

 

 

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