遍歷情況:
前序:根結點 ---> 左子樹 ---> 右子樹
中序:左子樹---> 根結點 ---> 右子樹
后序:左子樹 ---> 右子樹 ---> 根結點
例題一:
輸入描述 Input Description
輸入文件共2行,第一行表示該樹的前序遍歷結果,第二行表示該樹的后序遍歷結果。輸入的字符集合為{a-z},長度不超過26。
輸出描述 Output Description
輸出文件只包含一個不超過長整型的整數,表示可能的中序遍歷序列的總數。
樣例輸入 Sample Input
abc
cba
樣例輸出 Sample Output
4
思路:
由以上的前中后遍歷順序可以看出在已知前序遍歷和后序遍歷的情況下,中序遍歷不是唯一確定的。而且中序遍歷的不確定性是由一個節點(只有一邊子樹)的左右子樹的不確定性決定的。例如前序遍歷ab,后序遍歷ba,a為根,b為子樹,在中序遍歷中如果b為左子樹,則中序遍歷為ba;如果b為右子樹,則中序遍歷為ab。所以當這種節點有n個時,中序遍歷的可能性就有:2^n;
那么問題就轉變為如果確定這種節點的數量。可以總結出一個規律,如上例。前序遍歷為ab,后序遍歷為ba,此時無法確定b是為左子樹還是右子樹,那么就產生了一個特殊節點。所以規律就是(此時a,b分別為前序遍歷和后序遍歷的字符串):a[i]==b[j]時,a[i+1]==b[j-1]則產生一個特殊節點
代碼:
#include<iostream> #include<stdio.h> #include<math.h> #include<string.h> using namespace std; int main(){ string a,b; cin>>a; cin>>b; int cnt = 0; int len1 = a.length(); int len2 = b.length(); for(int i=0;i<len1;i++){ for(int j=1;j<len2;j++){ if(a[i]==b[j]&&a[i+1]==b[j-1]){ cnt++; } } } cout<<pow(2,cnt)<<endl; return 0; }
例題二:
輸入:第一行輸入二叉樹的結點數n
第二行輸入前序遍歷的結點編號序列,相鄰編號用空格隔開
第3行輸入中序遍歷的結點編號序列,相鄰編號用空格隔開
結點編號為從1至n的整數,請注意,1不一定是根節點
輸出:
在1行中輸出按后序遍歷時的結點編號序列。相鄰結點編號之間用1個空格隔開。
限制:1<=結點數<=100
輸入示例:
5
1 2 3 4 5
3 2 4 1 5
輸出示例:
3 4 2 5 1
代碼:
#include<iostream> #include<stdio.h> #include<vector> #include<algorithm> using namespace std; vector<int>pre,in,post; int n,pos; void rec(int l,int r){ if(l>=r) return ; int root = pre[pos++]; int m = distance(in.begin(),find(in.begin(),in.end(),root)); rec(l,m); rec(m+1,r); post.push_back(root); } void solve(){ pos = 0; rec(0,pre.size()); for(int i=0;i<n;i++){ if(i) cout<<" "; cout<<post[i]; } cout<<endl; } int main(){ int k; cin>>n; for(int i=0;i<n;i++){ cin>>k; pre.push_back(k); } for(int i=0;i<n;i++){ cin>>k; in.push_back(k); } solve(); return 0; }