You are to determine the value of the leaf node in a given binary tree that is the terminal node of a path of least value from the root of the binary tree to any leaf. The value of a path is the sum of values of nodes along that path.
Input
The input file will contain a description of the binary tree given as the inorder and postorder traversal sequences of that tree. Your program will read two line (until end of file) from the input file. The first line will contain the sequence of values associated with an inorder traversal of the tree and the second line will contain the sequence of values associated with a postorder traversal of the tree. All values will be different, greater than zero and less than 10000. You may assume that no binary tree will have more than 10000 nodes or less than 1 node.
Output
For each tree description you should output the value of the leaf node of a path of least value. In the case of multiple paths of least value you should pick the one with the least value on the terminal node.
Sample Input
3 2 1 4 5 7 6
3 1 2 5 6 7 4
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
255
255
Sample Output
13
255
1.解题思路:
题目给出了一个二叉树的中序遍历和后续遍历,学过数据结构的同学们都知道,二叉树有许多奇特的性质,其中包含一条就是已知二叉树的先序和中序遍历我们可以求出后序遍历;已知二叉树的中序遍历和后序遍历我们可以求出二叉树的先序遍历。
前序遍历的规则是根左右,后序遍历的规则是左右根,中序遍历的规则是左根右,所以在后序遍历中的最后一个被访问的节点就是根节点;前序遍历中的第一个被访问的结点就是根结点:
in 3 2 1 4 5 7 6
lch r rch
post 3 1 2 5 6 7 4
root
当找到根节点后带回到中序遍历中,在中序遍历里找到根节点的位置,根节点的左边的节点们就在根节点的左子树上,右半部分就是根节点的右子树,然后再分别对左右子树做如上处理,一切交给递归去解决吧~然后就能建好一棵树了。
已知先序遍历和中序遍历时,处理方法类似,先序遍历最先访问的是根节点,所以根节点应该在第一个位置。
题目最后要求的是一条从根到叶子节点的权值最小的路,从叶子节点向上DFS到根即可。
2.C++语言方面细节:
- 1.cin.getline是针对数组字符串的,以指定的地址为存放第一个读取的字符的位置,依次向后存放读取的字符,直到读满N-1个,或者遇到指定的结束符为止。全局函数的getline(cin,str);处理后还留有结束符在输入流中,故需要使用cin.get();//接受最后一个结束符,才能接受后面得输入值。getline(cin,str)函数是处理string类的函数。第二个参数为string类型的变量。读入时第二个参数为string类型,而不是char*,要注意区别。getline()函数的定义如下所示:
1. istream& getline ( istream &is , string &str , char delim );
2. istream& getline ( istream &is , string &str );
is 进行读入操作的输入流。
str 用来存储读入的内容。
delim 终结符,遇到该字符停止读取操作,不写的话默认为回车,如定义2中的示例。
- 2.stringstream是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的iostream、fstream有类似的操作方式。要使用stringstream, 必须先加入这一行:#include <sstream>.
stringstream主要是用在將一个字符串分割,可以先用.clear( )以及.str( )將指定字串设定成一开始的內容,再用>>把个別的资料输出。
<sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。
注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。
stringstream通常是用来做数据转换的。相比c库的转换,它更加安全,自动和直接.
//
// main.cpp
// suanfajingsai_6
//
// Created by 徐宝 on 2019/4/6.
// Copyright © 2019 xubao. All rights reserved.
//
#include <algorithm>
#include <cstdio>
#include <sstream>
#include <string>
#include <iostream>
#include <list>//双向链表
#include <stack>//栈
#include <queue>//队列
using namespace std;
//因为各结点的权值各不相同而且都是正整数,直接用权值作为结点编号
const int maxv=10000+10;
int in_order[maxv],post_order[maxv],lch[maxv],rch[maxv];
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;
}
//把in_order[L1...R1]和post_order[L2...R2]建成一棵二叉树,返回树根
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; //左子树的结点个数
lch[root]=build(L1, p-1, L2, L2+cnt-1);
rch[root]=build(p+1, R1, L2+cnt, R2-1);
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() {
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<<endl;
}
return 0;
}