1. 题目描述: 点击链接 https://cn.vjudge.net/problem/UVA-548
2. 问题分析:
题目已经给出了某二叉树经过中序遍历和后序遍历得到的节点顺序, 要求通过这些节点的值以及顺序, 找到原有的二叉树以及到根节点最近的叶子节点.
我认为最主要的是找到后序遍历和中序遍历得到的节点顺序有什么规律
我们知道, 中序遍历首先遍历左子树, 然后访问根结点, 最后遍历右子树, 而后序遍历首先遍历左子树, 然后遍历右子树, 最后访问根节点. 所以由此我们不难得出以下几个结论:
(1) 中序遍历的左子树和右子树分布于根节点的两侧.
(2) 后序遍历最后一个值一定是根节点,
(3) 这两种遍历方法都是可以使用递归, 任何一个左子树和右子树都可以看成另外一颗完整的二叉树
3. 算法步骤:
(1) 通过后序遍历给的值找到根节点, 在利用找到的根节点在中序遍历给的值中找到左子树和右子树
(2) 通过递归, 还原出完整的二叉树
(3) 使用 DFS 找到路径最短的路线
4.ac 代码:
- #include<iostream>
- #include<string>
- #include<stdlib.h>
- #include<sstream>
- #include<algorithm>
- using namespace std;
- const int maxn=10000+10;
- int in_order[maxn],post_order[maxn],lch[maxn],rch[maxn];
- int n;
- bool read_list(int *a){
- string line;
- if(!getline(cin,line))return false;
- stringstream ss(line);
- n=0;
- int x;
- while(ss>>x)a[n++]=x;
- return n>0;
- }
- int build(int L1,int R1,int L2,int R2){// 建二叉树, 返回树根
- if(L1>R1)return 0;// 空树
- int root=post_order[R2];
- int p=L1;
- while(in_order[p]!=root)p++;
- int cnt=p-L1;// 左子树的节点个数
- cout<<"L1,p-1,L2,L2+cnt-1"<<endl;
- cout<<L1<<""<<p-1<<" "<<L2<<" "<<L2+cnt-1<<endl;
- lch[root]=build(L1,p-1,L2,L2+cnt-1);
- cout<<"lch["<<root<<"]="<<lch[root]<<endl;
- cout<<"p+1,R1,L2+cnt,R2-1"<<endl;
- cout<<p+1<<""<<R1<<" "<<L2+cnt<<" "<<R2-1<<endl;
- rch[root]=build(p+1,R1,L2+cnt,R2-1);
- cout<<"rch["<<root<<"]="<<rch[root]<<endl;
- return root;
- }
- int best,best_sum;
- void dfs(int u,int sum){
- sum+=u;
- if(!lch[u]&&!rch[u]){
- if(sum<best_sum||(sum==best_sum&&u<best)){best=u;best_sum=sum;}
- }
- if(lch[u])dfs(lch[u],sum);
- if(rch[u])dfs(rch[u],sum);
- }
- int main(){
- //freopen("in.txt","r",stdin);
- while(read_list(in_order)){
- read_list(post_order);
- build(0,n-1,0,n-1);
- best_sum=1000000000;
- dfs(post_order[n-1],0);
- cout<<best<<"\n";
- }
- return 0;
- }
来源: http://www.bubuko.com/infodetail-2825693.html