目錄
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!]