PAT1119
点击查看题目
题意给出二叉树的先序遍历与后序遍历,要求判断据两序列重构的二叉树是否唯一。
唯一输出Yes并且输出中序遍历,不唯一输出No,然后输出任意中序遍历。
这个题我想了好半天可能太笨了吧,之前写过先序加中序,还有后序加中序,那些都是在书上看的题解然后自己写的,这个自己想了一会觉得还是很有意思的。
先说怎么根据先序还有后序重建二叉树我是每次都把后序的最后一个元素当根来写的,后序的最后一个元素当作根,后序的倒数第二个元素只有两种情况:
1.后序最后一个元素的右孩子。
2.是后序结点的左孩子。
注意都是孩子,不是子树,而且题目说能不能构建出唯一的树,那么说明有些情况是可以确定左右孩子的,能确定的时候就可以构造出正确的,不能确定的时候就构造出不确定的。
那么什么时候确定呢?
我观察发现 当先序序列与后序序列缩短到2时根的左右孩子时不能确定的。
比如:
先序:1 , 2
后序:2, 1
2是不是可以当左子孩子,也可以当右孩子? 为什么会不能确定呢? 应为1少了一个孩子,它不是所有孩子都建在,先序是根左右,后序是左右根。试想如果少了一个孩子。则 先序是左根,后序是根左, 还是 先序是右根, 后序是根右,谁能确定?? 但是如果孩子没有少, 应为先序遍历的性质,
左孩子后面一定是右孩子,右孩子后面一定是根。左右之分就出来了。
可以模拟一下 先序 1 2 3 后序 2 3 1,就能想到。
总结一下,判断重建的树是不是唯一其实就是看这个树的节点的孩子是否都建在,即除了叶子结点没孩子,其他结点的左右孩子都在。
根据后序还有先序怎么重建二叉树:
把后序最后一个当作根, 然后在先序里面查找后序倒数(postR - 1)第二个对应的下标,postR-1这个数前面也说了一定是左右孩子其中的一个,所有直接当作右孩子就行了,因为是左是还是右无所谓,打个比方如果真的是右!好我们建树对了,然后再判断是否唯一就行,如果不是右孩子,无所谓啊,因为如果答案唯一,这个孩子就应该是右孩子,既然不是右孩子,我们判断的时候就会判断出答案不唯一,反正不影响。
扯远了,在先序里面查找postR-1对应的下标,因postR-1是根的右孩子,则对应到先序中应当是根左右 右部分对应的第一个元素,哈哈哈,想到这里文就茅塞顿开啊!这样不就确定了,该根左右子树对应的先序还有后序序列了吗???然后递归下去,直到没有元素可以划分为止。想到这里在实现的时候就很类似与知道先序后者后序,与中序求数的题目了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 31;
int pre[N];
int post[N];
int nums = 0;
struct node {
int data;
node *lchild, *rchild;
};
node* newNode(int x) {
node* Node = new node;
Node->data = x;
Node->lchild = Node->rchild = NULL;
return Node;
}
node* rebuild(int prel, int prer, int pol, int por) {
if(pol > por) return NULL; //这里为啥会有两个判断? 一个pro - pol 一个 pol > por ?
node* root = newNode(post[por]); // 用 per 1 2 3 posr 3 2 1 , pre 1 2 3 post 2 3 1模拟即可。
if(por - pol == 0) return root;
int k = prel;
for(; k <= prer; k++) {
if(pre[k] == post[por-1]) break;
}
int Leftnums = k- prel - 1; // post 左子树的个数
root->lchild = rebuild(prel+1, k-1, pol, pol + Leftnums - 1);
root->rchild = rebuild(k, prer, pol + Leftnums, por - 1);
return root;
}
void inorder(node* root, int n) { //中序遍历
if(root == NULL) return;
inorder(root->lchild, n);
printf("%d", root->data);
nums++;
if(nums < n) printf(" ");
else printf("\n");
inorder(root->rchild, n);
}
bool judge(node* root) {
if(root == NULL) return true;
if(root->lchild != NULL && root->rchild ==NULL || root->rchild
!= NULL && root->lchild ==NULL) return false; //判错因子
return judge(root->lchild) && judge(root->rchild);
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &pre[i]);
for(int i = 0; i < n; i++) scanf("%d", &post[i]);
node* root = rebuild(0,n-1, 0, n-1);
if(judge(root)) printf("Yes\n");
else printf("No\n");
inorder(root, n);
return 0;
}
我为了证实我的推论,就是当先序与后序长度为2时生成的二叉树不唯一,我直接就用这个来判断是否时唯一的二叉树了。即在重构的时候判断是否有一层dfs里面 先序后序的长度为2? 有直接令全局变量为true, 我认为长度为2的先序后序序列的出现直接就导致该树构造不唯一,我把代码中判错的judge用上述方法替代了,通过此题。
总结,据先序后序重构时,不出现先序后序长度为2的情况,此树唯一!
#include<bits/stdc++.h>
using namespace std;
const int N = 31;
int pre[N];
int post[N];
int nums = 0;
bool flag = false;
struct node {
int data;
node *lchild, *rchild;
};
node* newNode(int x) {
node* Node = new node;
Node->data = x;
Node->lchild = Node->rchild = NULL;
return Node;
}
node* rebuild(int prel, int prer, int pol, int por) {
if(por - pol + 1 == 2 && prer - prel + 1 == 2) flag = true; //有长度为2的先序后序就判不唯一!
if(pol > por) return NULL;
node* root = newNode(post[por]);
if(por - pol == 0) return root;
int k = prel;
for(; k <= prer; k++) {
if(pre[k] == post[por-1]) break;
}
int Leftnums = k- prel - 1;
root->lchild = rebuild(prel+1, k-1, pol, pol + Leftnums - 1);
root->rchild = rebuild(k, prer, pol + Leftnums, por - 1);
return root;
}
void inorder(node* root, int n) {
if(root == NULL) return;
inorder(root->lchild, n);
printf("%d", root->data);
nums++;
if(nums < n) printf(" ");
else printf("\n");
inorder(root->rchild, n);
}
//bool judge(node* root) {
// if(root == NULL) return true;
// if(root->lchild != NULL && root->rchild ==NULL || root->rchild != NULL && root->lchild ==NULL) return false;
// return judge(root->lchild) && judge(root->rchild);
//
//}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &pre[i]);
for(int i = 0; i < n; i++) scanf("%d", &post[i]);
node* root = rebuild(0,n-1, 0, n-1);
if(!flag) printf("Yes\n"); //全局代替了判错函数judge
else printf("No\n");
inorder(root, n);
return 0;
}