1119. Pre- and Post-order Traversals (30)

友情提示:这题非常值得自己思考独立做出来,请反复确认后再往下拉


1119. Pre- and Post-order Traversals (30)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Special
作者
CHEN, Yue

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique.

Now given a pair of postorder and preorder traversal sequences, you are supposed to output the corresponding inorder traversal sequence of the tree. If the tree is not unique, simply output any one of them.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first printf in a line "Yes" if the tree is unique, or "No" if not. Then print in the next line the inorder traversal sequence of the corresponding binary tree. If the solution is not unique, any answer would do. It is guaranteed that at least one solution exists. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input 1:
7
1 2 3 4 6 7 5
2 6 7 4 5 3 1
Sample Output 1:
Yes
2 1 6 4 7 3 5
Sample Input 2:
4
1 2 3 4
2 4 3 1
Sample Output 2:
No
2 1 3 4
题意:给出树的前序后序遍历,输出中序。不能确定时,任选一种输出

分析:和前中、后中一样,我们需要找到前后遍历的特殊点

           我最先感觉,pre的最后一个(5)和post的第一个(2),分别代表mid中最右和最左

           然后发现 如果pre的第一个(1) 和post的最后一个(1)相等,那么1是根节点

           _(:з」∠)_接着就迫不及待开始做了,一顿骚操作以后我发现还做不了

          再看的时候发现:虽然单看pre没办法 确定(2)是(1)的左子树还是右子树,但是(1)在post中的前一个是(3),那么(3)要么是(1)的左子树要么是(1)的右子树,而pre当中(2)再过去才是(3),所以说明,(2)是(1)的左子树,(3)是(1)的右子树。那么剩下的(4)(5)(6)(7)呢? 再确认,(2)和(3)分开以后,(4)(5)(6)(7)明显就只能是(3)的子树

          有了这一点,就可以开始做了

          用递归分治,对(3)的左右子树再分别判断,逐步缩小,直至确认。以下图做详细说明


 1.首先我们发现post(1)  前一位是 3,对应到pre(3)当中pre(3)与pre(1)中有间隔。说明:(2)是(1)的左子树,(3)是(1)的右子树

         2.开始递归,在橙色圈中我们可以发现,(5)是(3)的右子树,(4)是3的左子树

         3.post(4)前一位(7)对应到pre当中与pre(4)中间仍然数字间隔,所以(6)是(4)的左子树,(7)是(4)的右子树

         4.(1)的左子树(2),可以看出左边是(1)不能用,右边则都在(3)的范围内,所以(2)两个子树为空

         5.(3)的右子树(5),同上,两个子树为空

          

         那么,我们要怎么判断有没有唯一解呢?如果每一个非叶节点都像上面(1)(3)(4)一样,显然是有唯一解的,但是如果题中第二个例子的(3),它的子树(4)是与(3)紧连的,中间没有数字隔开,这是就无法判断是左子树还是右子树。所以只要当我们发现有某个非叶节点只有一个孩子的时候,就可以输出No了

代码:

#include<iostream>
using namespace std;
int pre[40]={0};
int post[40]={0};
int n,judge=1;
struct node {
	int data;
	struct node *lchild,*rchild;
};
int find(int a[],int data){
	for(int i=0; i<n; i++)
		if(a[i] == data) return i;
}
struct node *creat(struct node *root, int preStart, int preEnd, int postStart, int postEnd){
	if(pre[preStart] == post[postEnd]){
		root = new struct node();
		root->data = pre[preStart];
	} 
	if(preStart == preEnd || postStart == postEnd) return root;	
	int i = find(pre, post[postEnd - 1]);//i是root右孩子在pre的索引 
	int j = find(post, pre[preStart + 1]);//j是root左孩子在post的索引 	
	if(i - preStart >= 2) {	
		root->lchild = creat(root->lchild, preStart+1, i-1, postStart, j);
		root->rchild = creat(root->rchild, i, preEnd, j+1, postEnd-1);
	}
	else{//其实只剩一种可能,即 i == preStart+1 
		judge=0;
		root->rchild = creat(root->rchild, i, preEnd, j+1,postEnd-1);
	}
	return root;
}
void midOut(struct node* root){
	static int cnt=0;
	if(root->lchild) midOut(root->lchild);
	if(root) cnt == 0 ? cout<< root->data : cout<<" "<<root->data;
	cnt++;
	if(root->rchild) midOut(root->rchild);
}
int main()
{
	cin>>n;	
	for(int i=0; i<n; i++)
		cin>>pre[i];
	for(int i=0; i<n; i++)
		cin>>post[i];
	struct node *root;
	root = creat(root, 0, n-1, 0, n-1);
	judge==1? cout<<"Yes"<<endl:cout<<"No"<<endl;
	midOut(root);
	cout<<endl;
}

结尾:这题感觉有些可惜,因为前面想了很久,中间试过很多“奇思妙想”的方法,当我想到先确认根再确认左右子树时,预估代码要写八九十行而且很繁琐,就忍不住看了别人的题解。 结果发现就是这个思路 _(:з」∠)_。  不过那时候没想到递归,还在扑哧扑哧上下左右想着点,所以弄的很复杂。  不过人家直接数组就记录了mid,然后直接输出,感觉还是很炫酷。


          



转载于:https://www.cnblogs.com/childwang/p/8280262.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值