例1:给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。
题目链接:https://www.patest.cn/contests/gplt/L2-006
#include
using namespace std;
const int MAXN = 100 + 10;
int post[MAXN], in[MAXN];
int lchild[MAXN], rchild[MAXN];
vector ans;
int dfs(int pL, int pR, int iL, int iR, int root){
if(pL > pR) return 0;
int id = iL;
while(in[id] != root) ++id;
int cnt = id - iL;
lchild[root] = dfs(pL, pL + cnt - 1, iL, id - 1, post[pL + cnt - 1]);
rchild[root] = dfs(pL + cnt, pR - 1, id + 1, iR, post[pR - 1]);
return root;
}
void bfs(int root){
queue q;
q.push(root);
while(!q.empty()){
int x = q.front();
ans.push_back(x);
q.pop();
if(lchild[x]) q.push(lchild[x]);
if(rchild[x]) q.push(rchild[x]);
}
}
int main(){
int N;
scanf("%d", &N);
for(int i = 0; i < N; ++i){
scanf("%d", &post[i]);
}
for(int i = 0; i < N; ++i){
scanf("%d", &in[i]);
}
int root = post[N - 1];
dfs(0, N - 1, 0, N - 1, root);
bfs(root);
int len = ans.size();
for(int i = 0; i < len; ++i){
printf("%d", ans[i]);
if(i == len - 1) printf("\n");
else printf(" ");
}
return 0;
}
例2:已知前序遍历和中序遍历,求后序遍历。
题目链接:https://www.patest.cn/contests/pat-a-practise/1138
#include
using namespace std;
const int MAXN = 50000 + 10;
int pre[MAXN], in[MAXN];
vector ans;
void dfs(int pL, int pR, int iL, int iR, int root){
if(pL > pR) return;
int id = iL;
while(in[id] != root) ++id;
int cnt = id - iL;
dfs(pL + 1, pL + cnt, iL , id - 1, pre[pL + 1]);
dfs(pL + cnt + 1, pR, id + 1, iR, pre[pL + cnt + 1]);
ans.push_back(root);
}
int main(){
int N;
scanf("%d", &N);
for(int i = 0; i < N; ++i){
scanf("%d", &pre[i]);
}
for(int i = 0; i < N; ++i){
scanf("%d", &in[i]);
}
int root = pre[0];
dfs(0, N - 1, 0, N - 1, root);
printf("%d\n", ans[0]);
return 0;
}
另一种做法:
因为输出的是后序遍历(左右中)第一个元素,因此对于某元素,
如果有左子树的话,就不用研究右子树了;
如果没有左子树,就研究右子树;
如果左右子树都没有,就研究他本身。(遇到的第一个叶子结点就是答案)
#include
using namespace std;
const int MAXN = 50000 + 10;
int pre[MAXN], in[MAXN];
map mp;
void dfs(int pL, int pR, int iL, int iR, int root){
if(pL > pR) return;
int id = mp[root];
int cnt = id - iL;
if(iL != id){
dfs(pL + 1, pL + cnt, iL, id - 1, pre[pL + 1]);
}
else if(iR != id){
dfs(pL + cnt + 1, pR, id + 1, iR, pre[pL + cnt + 1]);
}
else{
printf("%d\n", root);
return;
}
}
int main(){
int N;
scanf("%d", &N);
for(int i = 0; i < N; ++i){
scanf("%d", &pre[i]);
}
for(int i = 0; i < N; ++i){
scanf("%d", &in[i]);
mp[in[i]] = i;
}
int root = pre[0];
dfs(0, N - 1, 0, N - 1, root);
return 0;
}
例3:已知前序遍历和后序遍历,求中序遍历。
思路:前序遍历的第一个元素是根。
若只有左子树,则前序遍历的第二个元素和后序遍历的倒数第二个元素相同,且都是左子树的根;
若只有右子树,则前序遍历的第二个元素和后序遍历的倒数第二个元素相同,且都是右子树的根;
若既有左子树又有右子树,则前序遍历的第二个元素是左子树的根,后序遍历的倒数第二个元素是右子树的根;
即,若前序遍历的第二个元素和后序遍历的倒数第二个元素相同,则对于当前根结点来说有两种可能,要么只有左子树,要么只有右子树。这两种情况下,前序遍历是相同的,后序遍历也是相同的,但中序遍历不同。
(1)求任意一种中序遍历。
题目链接:https://www.patest.cn/contests/pat-a-practise/1119
#include
#include
#include
(2)求中序遍历可能的种数。
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1832
思路:运算结果涉及高精度计算。
#include
#include
#include