美国血统问题
题目描述
农夫约翰非常认真地对待他的奶牛们的血统。然而他并不是一个优秀的记帐员。他把他的奶牛们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而不是用图形的方法。你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母(你可能已经知道你可以在知道树的两种遍历以后可以经常地重建这棵树)显然这棵树不会有多于26个的顶点。)下图为样例输入和样例输出中的树。
输入描述
第一行:树的中序遍历,第二行:树的前序遍历
输出描述
一行,表示树的后序遍历
样例
输入
ABEDFCHG
CBADEFGH
输出
AEFDBHGC
思路
观察题目,我们不要被那一大串的题目描述和看起来牛*轰轰的题目吓傻,概括一下要干什么:
就是给你一棵树的前序遍历和中序遍历,让你求后序遍历
我们先理一下不用程序,把它当一道数学题怎么做
简单来说,就是利用前序遍历根左右的顺序确定根节点,再利用中序遍历左右根的特点确定左右子树分别含有什么点,最后重复上述过程即可
那我们思考一下,上面的实现过程有一个关键词“重复”,而树的遍历我们又通常通过搜索实现,易得应该使用深度优先搜索
d
f
s
dfs
dfs
首先我们先定义两个字符串用来存前根遍历和中根遍历,再在dfs函数中传进两字符串的开始和结束好做处理
在函数中,因为要对字符串进行处理,所以首先要判断当前字符串是否合法,然后再判断当前字符串是否只有一个字符,如果是就不用进行处理因为代表已经找到了当前部分的答案直接输出再
r
e
t
u
r
n
return
return掉即可
判断完上边的都不成立后,开始处理
因为本题本质上我们要通过递归实现,找出根节点后再的将分出的左右子树丢给下一次递归进行处理即可,因为当分无可分时就会从前面的判断是否查找完毕
r
e
t
u
r
n
return
return掉
如此即可
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n, x;
string s1, s2; //用来存前序和中序遍历
void dfs(int l1, int r1, int l2, int r2) {
//判断是否合法
if (r1 < l1 || r2 < l2) {
return;
}
//判断是否已经查找完
if (l1 == r1) {
printf("%c", s1[l1]);
return;
}
int m = s1.find(s2[l2]), len = m - l1; //找根节点
//将找出的左右子树丢进递归进行下一次即可
if (m > l1) {
dfs(l1, m - 1, l2 + 1, l2 + len);
}
if (m < r1) {
dfs(m + 1, r1, l2 + len + 1, r2);
}
printf("%c", s2[l2]);
}
int main() {
cin >> s1 >> s2;
int len_s1 = s1.length() - 1;
dfs(0, len_s1, 0, len_s1);
return 0;
}