友情提示:这题非常值得自己思考独立做出来,请反复确认后再往下拉
1119. Pre- and Post-order Traversals (30)
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 1Sample Output 1:
Yes 2 1 6 4 7 3 5Sample Input 2:
4 1 2 3 4 2 4 3 1Sample 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,然后直接输出,感觉还是很炫酷。