我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805353470869504
题目描述:
题目翻译:
1119 前序遍历和后序遍历
假设二叉树中的所有键都是不同的正整数。给定一对后序和中序遍历序列或前序和中序序列可以唯一地确定一棵二叉树。但是,如果仅给出后序和前序遍历序列,则相应的树可能不再是唯一的。
现在给出一对后序和前序遍历序列,你需要输出树的相应的中序序列。如果树不是唯一的,只需输出其中任何一个。
输入格式:
每个输入文件包含一个测试用例。对于每个测试用例,第一行给出正整数N(<= 30),代表二叉树中的节点总数。第二行给出前序序列,第三行给出后序序列。一行中的所有数字都用空格分隔。
输出格式:
对于每个测试用例,如果树是唯一的,则首先在一行打印“Yes”,否则打印“No”。然后在下一行打印相应二叉树的中序序列。如果解决方案不是唯一的,那么任何答案都可以。题目保证至少存在一种解决方案。一行中的所有数字必须用一个空格分隔,并且行末不能有额外的空格。
输入样例1:
7
1 2 3 4 6 7 5
2 6 7 4 5 3 1
输出样例1:
Yes
2 1 6 4 7 3 5
输入样例2:
4
1 2 3 4
2 4 3 1
输出样例2:
No
2 1 3 4
知识点:重建二叉树、中序遍历
思路:根据前序遍历结果和后序遍历结果重建该二叉树,再中序遍历之
如何判断二叉树是否唯一?又如何根据前序遍历结果和后序遍历结果重建该二叉树呢?
以2个样例进行分析说明。
样例1的分析说明:
1 2 3 4 6 7 5
2 6 7 4 5 3 1
(1)首先我们明确其根节点是1,此时我们的二叉树如下图所示。
(2)如何判别左右子树各有哪些节点呢?
对于前序序列的第2个值是2,我们在后序序列中找到其位置,是第1个值,因此我们说左子树只有一个元素,是2,右子树有5个元素,分别是3 4 6 7 5,这样我们就确定了1的左孩子是2,此时我们的二叉树如下图所示。
(3)这时候我们未确定的序列是:
3 4 6 7 5
6 7 4 5 3
我们知道这些值一定在1的右子树中,而1的右子树的根结点由上述两序列知是3。此时我们的二叉树如下图所示。
(4)对于前序序列的第2个值是4,我们在后序序列中找到其位置,是第3个值,因此我们说左子树有3个元素,是4 6 7,右子树有1个元素,是5,这样我们就确定了3的右孩子是5,此时我们的二叉树如下图所示。
(5)这时候我们未确定的序列是:
4 6 7
6 7 4
我们知道这些值一定在3的左子树中,而3的左子树的根结点由上述两序列知是4。此时我们的二叉树如下图所示。
(6)对于前序序列的第2个值是6,我们在后序序列中找到其位置,是第1个值,因此我们说左子树只有1个元素,是6,右子树有1个元素,是7,这样我们就确定了4的左右孩子分别是6和7,此时我们的二叉树已经完全确定,如下图所示。
其中序遍历结果是2 1 6 4 7 3 5,整个过程中所有过程唯一确定,因此该二叉树唯一
样例2的分析说明:
(1)首先我们明确其根节点是1,此时我们的二叉树如下图所示。
1 2 3 4
2 4 3 1
(2)如何判别左右子树各有哪些节点呢?
对于前序序列的第2个值是2,我们在后序序列中找到其位置,是第1个值,因此我们说左子树只有一个元素,是2,右子树有2个元素,分别是3 4,这样我们就确定了1的左孩子是2,此时我们的二叉树如下图所示。
(3)这时候我们未确定的序列是:
3 4
4 3
我们知道这些值一定在1的右子树中,而1的右子树的根结点由上述两序列知是3。此时我们的二叉树如下图所示。
(4)此时不确定的元素只有1个,就是4,我们只知道4是3的左孩子或是右孩子,但无法确定4到底是3的左孩子还是右孩子。因此就产生如下图所示的两棵树。如果按照之前的思路,4应该是3的左孩子,而3的右孩子为空,得到下图中的左图。
其中序遍历结果分别是2 1 4 3和2 1 3 4。
由上述两种情况的分析我们可以看到,二叉树不唯一的情况出现在不确定的元素只有1个的时候,这时候我们既可以将其当成是当前节点的左孩子,也可以当成是当前节点的右孩子。
而在代码实现中,我们只需在递归过程中加一个标记位flag来标记该二叉树是否唯一即可。
时间复杂度和空间复杂度均是O(N)。
C++代码:
#include<iostream>
#include<set>
#include<vector>
using namespace std;
struct node{
int data;
int lchild, rchild;
};
node Node[30];
int index = 0;
bool flag = true;
int preOrder[30];
int postOrder[30];
vector<int> inOrder;
int create(int preLeft, int preRight, int postLeft, int postRight);
void inOrderTraversal(int head);
int main(){
int N;
scanf("%d", &N);
for(int i = 0; i < N; i++){
scanf("%d", &preOrder[i]);
}
for(int i = 0; i < N; i++){
scanf("%d", &postOrder[i]);
}
int head = create(0, N - 1, 0, N - 1);
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
inOrderTraversal(head);
for(int i = 0; i < inOrder.size(); i++){
printf("%d", inOrder[i]);
if(i != inOrder.size() - 1){
printf(" ");
}else{
printf("\n");
}
}
return 0;
}
int create(int preLeft, int preRight, int postLeft, int postRight){
if(preLeft > preRight){
return -1;
}
if(preLeft + 1 == preRight){
flag = false;
}
int head = index++;
Node[head].data = preOrder[preLeft];
int numLeft = 0;
for(int i = postLeft; i <= postRight - 1; i++){
if(postOrder[i] == preOrder[preLeft + 1]){
numLeft = i - postLeft + 1;
break;
}
}
Node[head].lchild = create(preLeft + 1, preLeft + numLeft, postLeft, postLeft + numLeft - 1);
Node[head].rchild = create(preLeft + numLeft + 1, preRight, postLeft + numLeft, postRight - 1);
return head;
}
void inOrderTraversal(int head){
if(head == -1){
return;
}
inOrderTraversal(Node[head].lchild);
inOrder.push_back(Node[head].data);
inOrderTraversal(Node[head].rchild);
}
C++解题报告: