题目相关
农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形的方法。
你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的 后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母。(你可能已经知道你可以在知道树的两 种遍历以后可以经常地重建这棵树。)显然,这里的树不会有多于 26 个的顶点。 这是在样例输入和 样例输出中的树的图形表达方式:
树的中序遍历是按照左子树,根,右子树的顺序访问节点。
树的前序遍历是按照根,左子树,右子树的顺序访问节点。
树的后序遍历是按照左子树,右子树,根的顺序访问节点。
输入格式
第一行: 树的中序遍历
第二行: 同样的树的前序遍历
输出格式
单独的一行表示该树的后序遍历。
输入输出样例
输入
ABEDFCHG
CBADEFGH
输出
AEFDBHGC
题解相关
自己的
思路
首先分析题目,题目简单来看就是根据二叉树的先序和中序(来确定二叉树)输出后序。根据三种遍历的特点我们可以:
- 因为先序最方便找到的也是第一个字符,就是根,而中序可以通过根来分割左子树和右子树,我们可以简单地构思出一个DFS的函数。
- 先序找到根,中序找到该根的左右子树,dfs先进右子树,找到根,左右子树……后进左子树,找到根,左右子树……最后只剩根输入。
- 因为后序左右根的特征,所以要将我们先前输入的顺序整个颠倒过来,最后输出即可。
问题
- 递归结束条件?答:进入函数的字符串为空串
- 进入递归的条件?答:进入左右子树的DFS时要先判断该根是否有左右子树,无的话就会发生越界等不可预知的情况!
- 如何颠倒?答:算法库里的reverse函数。
别人的
字符串切割时应注意的问题
那便是切割位置。STL的string类型自带切割方法substr,但搞不清参数就会导致WA甚至RE。
首先我们搞清楚substr方法的使用方法。
string s;
s.substr(order,k);
参数传入一个order,一个k。
函数将会从下标为order的位置开始,连续截取k个字符。返回截取后的字符串。
order显然不能超出0~s.size()-1的范围。
但是,如果order+k超过了s.size()-1,函数会自动只截取到s的末尾。
如果不传入k,那么默认截取到末尾。
这个函数是返回一个字符串,而不是对s进行改动。
s.find ( c );
//在字符串s中查找第一个字符c的位置,返回下标,如果没有返回string::nposs.erase(it);
//在字符串中删除指针it所指向的字符s.begin();
//返回s的首字符的指针(迭代器)
代码
自己的
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
string pre, in, post;
void PostAH(string pre, string in){
if(pre.size()>1){
char ch=pre[0];
post+=ch;
int i=in.find(ch);//根在中序的位置
//int l=in.substr(0,i).size();//左子树长度 //l不就等于i吗……
if(i!=in.size()-1) //有右子树
PostAH(pre.substr(i+1), in.substr(i+1));//右子树
if(i!=0)//有左子树
PostAH(pre.substr(1,i), in.substr(0,i));//左子树
}
else if(pre.size()==1) post+=pre;
}
int main()
{
cin>>in;
cin>>pre;
PostAH(pre, in);
reverse(post.begin(), post.end());
cout<<post;
return 0;
}
别人的
#include<string>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
string pre,inor;
void work(string pre,string inor)
{
if(pre.empty())return;
//如果序列空了,就没必要继续了
char root=pre[0];
//取到前序序列的首字母,即根节点
int k=inor.find(root);
//找到中序序列中根节点的位置
pre.erase(pre.begin());
//删去前序序列中的根节点
string leftpre=pre.substr(0,k);
//从0开始切割k个
string rightpre=pre.substr(k);
//从k开始切割到最后
string leftinor=inor.substr(0,k);
//从0开始切割k个
string rightinor=inor.substr(k+1);
//从k+1开始切割到最后
work(leftpre,leftinor);
work(rightpre,rightinor);
printf("%c",root);
//因为要输出后序序列,所以是左右根
//先遍历左子树,再右子树,再根节点
}
int main()
{
cin>>inor>>pre;
work(pre,inor);
putchar('\n');
return 0;
}