题目大意:给出二叉树的先序和后序序列,判断能否构成一棵唯一的二叉树。并输出中序遍历的结果。
与常规问题不同,需要考虑怎么从先序和后序序列中得到左右子树。例如,先序序列的范围是[ prel, prer ],后序序列的范围是[ postl, postr ],那么,显然 prel 和 postr 对应的都是当前树的根节点 root,[prel +1, prer] 包含左右子树,prel + 1是左或右子树的根节点; [postl, postr-1]包含左右子树,postr - 1是左或右子树的根节点。如果 prel +1 和 postr - 1 对应的不是一个节点,说明左子树和右子树都存在;否则说明剩下的节点全在一棵子树上,就无法确定是左子树还是右子树,从而不唯一。如果 prel + 1 和 posrt -1 对应的不是同一个节点,那么在后序序列中找到 与prel + 1对应的节点,从它往左就是左子树(含它本身),从它往右就是右子树(不含它本身),从而可以进行递归。
这里要注意如果左右子树只存在一棵的话,左子树的节点数量如果用先遍历再减法的方式可能会算错,需要在遍历查找时累加左子树的节点数量,避免错误。另外一个坑点是必须在结尾必须输出换行符,否则会格式错误。
AC代码:
#include <vector>
#include <cstdio>
using namespace std;
struct Node
{
int data;
Node* left;
Node* right;
Node(int data):data(data), left(NULL), right(NULL){};
};
vector<int> pre;
vector<int> post;
bool determined = true;
Node* root = NULL;
void createFromPrePost(Node* &node, int prel, int prer, int postl, int postr)
{
if(prel > prer) return;
if(node == NULL) node = new Node(pre[prel]);
int index = postl, leftNum = 0;
for (index = postl; index < postr; ++index)
{
leftNum++;
if(post[index] == pre[prel + 1]) break;
}
if(index == postr - 1) determined = false;
createFromPrePost(node->left, prel+1, prel+leftNum, postl, index);
createFromPrePost(node->right, prel+leftNum+1, prer, index+1, postr-1);
}
void inOrder(Node* node, int N)
{
static int printCnt = 0;
if(node->left) inOrder(node->left, N);
printf("%d", node->data);
if(++printCnt < N) printf(" ");
else printf("\n");
if(node->right) inOrder(node->right, N);
}
int main()
{
int N;
scanf("%d", &N);
pre.resize(N);
post.resize(N);
for (int i = 0; i < N; ++i)
scanf("%d", &pre[i]);
for (int i = 0; i < N; ++i)
scanf("%d", &post[i]);
createFromPrePost(root, 0, N-1, 0, N-1);
if(determined) printf("Yes\n");
else printf("No\n");
inOrder(root, N);
return 0;
}