这个题的意思是给你一颗二叉树的前序和中序,让你求出这棵树后序的的第一个数字。
常规的思路应该是利用前序和中序建立一颗二叉树。
但是题目的要求是只需要后序的第一个数字,那我们可以考虑不用建树来解决这个问题。
第一次经过时输出是前序遍历,第二次时是中序,第三次时是后序。
那么一个点如果后序遍历的时候第一次经过就输出,那么说明它没有孩子节点。
那我们的问题就转变为找到遍历过程中第一个叶子节点(没有孩子的节点)
怎么找到他呢,二叉树的前序遍历和中序遍历的大致如下
中序遍历根节点的左边是左子树,右边是右子树。
前序遍历和第一个节点是根节点,根节点右侧的第一个节点是左子树的根节点。
这个叶子节点一定在左子树的左子树的左子树的.........上。不然不返回的话,这棵树就是一条直线。
叶子节点没有孩子节点,那么在中序遍历中它的左右子树区域都为空。
所以我通过遍历左子树的左子树的。。。。找到一个在中序上左右皆为空的点。
这个问题到这里就完了,但有一个小小的骚操作,在中序上找子树的根节点的时候,我一开始是用循环遍历找到这个点了,但是后来交了一次,超时了,有一个测试点始终过不去。
然后我就用一个一个数组来存储这个点在inorder上的位置,复杂度从O(n)降到了O(1)。
最后耗时25ms过掉这个题。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
using namespace std;
int preorder[51015];
int inorder[51015];
int node[10000005];
bool vis[51015];
int result=0;
int n,root;
void fun(int num)
{
root = preorder[num];
vis[ node[root] ] = 1;
if(node[root] == 0 && vis[1]==1)
{
result = 0;
return ;
}
else if(node[root] == n-1 && vis[n-2]==1)
{
result = n-1;
return ;
}
if(vis[node[root]-1]==1 && vis[node[root]+1]==1)
{
result = node[root];
return ;
}
fun(++num);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&preorder[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&inorder[i]);
node[ inorder[i] ] = i;
}
fun(0);
printf("%d\n",inorder[result]);
}