题目描述
假设二叉树中的所有键值都是不同的正整数。唯一的二元树可以通过给定的后序和顺序遍历序列,或前序和顺序遍历序列来确定。但是,如果仅给出后序和前序遍历序列,则相应的树可能不再是唯一的。
现在给出一对后序和前序遍历序列,您应该输出树的相应的中序遍历序列。如果树不是唯一的,只需输出其中任何一个。
Input
每个输入文件包含一个测试用例。对于每种情况,第一行给出正整数N(≤30),即二叉树中的节点总数。第二行给出预订序列,第三行给出后序序列。一行中的所有数字都用空格分隔。
Output
对于每个测试用例,如果树是唯一的,则首先是行中的Yes,否则是No。然后在下一行中打印相应二叉树的中序遍历序列。如果解决方案不是唯一的,那么任何答案都可以。保证至少存在一种解决方案。一行中的所有数字必须用一个空格分隔,并且行的末尾不能有额外的空格。
Solution
我们知道,对于一棵二叉树,如果有他的前序序列与中序序列,或者后序序列与中序序列就可以建立唯一的这棵树。然而,如果只有他的前序序列和后序序列该怎么办呢?
首先我们需要明白,为什么前序序列和后序序列不可以确定一棵唯一的树?
-
信息重叠与缺失:
-
前序序列的第一个元素和后序序列的最后一个元素都指出了树的根节点,这是两者共同信息。
-
前序序列中第二个元素到某个点是左子树的信息,后序序列从倒数第二个元素到前面某个点是右子树的信息,但是这些信息并不足以精确划分左右子树的边界,尤其当树中包含单边子树(只有左子树和右子树)时候。
因此我们可以发现,其实前序序列和后序序列无法构建唯一树的原因是,在存在单边子树时候,无法划分左右子树。
-
单分支子树问题:
-
当二叉树中存在只有左子树或只有右子树的情况时,仅凭前序和后序序列难以区分这两种情况。例如两个不同的二叉树可能有相同的前序和后序序列,则在本题中,我们将这种矛盾情况一律转化为右子树的情况,以构建一棵“唯一”的二叉树。
这样,我们便找到了这道题目的解法:尝试通过前序序列和后序序列去构建这颗二叉树,如果出现单分支子树问题,这里选择将其归为右子树,如此便可以递归求出中序序列
Code
#include <bits/stdc++.h>
using namespace std;
int n;
bool flag = true;
vector<int> In, Pre, Post;
void GetInSeq(int preL, int preR, int postL, int postR)
{
if(preL == preR) // 找到一个叶子节点,叶子节点的中序遍历就是他本身
{
In.push_back(Pre[preL]);
return;
}
if(Pre[preL] == Post[postR]) // 找到根节点
{
int idx = preL + 1;
int LNode;
while(idx < preR && Pre[idx] != Post[postR - 1]) // 找到右子树根节点, 整个过程是尝试划分左右子树的过程
idx++;
LNode = idx - preL - 1;
if(idx > preL + 1) // 找到了右子树根节点在前序遍历中的位置, 找左子树的中序遍历
{
GetInSeq(preL + 1, idx - 1, postL, postL + LNode - 1);
}
else // 找不到右子树的根节点,将左子树设为空,标记不为空
{
flag = false;
}
In.push_back(Pre[preL]); // 将根节点放入InSeq
GetInSeq(idx, preR, postL + LNode, postR - 1);
}
}
int main()
{
cin >> n;
Pre.resize(n);
Post.resize(n);
for (int i = 0; i < n; i++)
cin >> Pre[i];
for (int i = 0; i < n; i++)
cin >> Post[i];
GetInSeq(0, n - 1, 0, n - 1);
if(flag)
puts("Yes");
else
puts("No");
for (int i = 0; i < n; i++)
{
cout << In[i] << " ";
}
cout << endl;
return 0;
}
受教了,点个赞