1119 Pre- and Post-order Traversals (30 分) %%%%%%%%%

这个题把我这菜鸡治的服服帖帖!
题意:
给定先序和后序
问中序是否唯一并输出其中任意一个中序序列
思路:
首先知道为啥没有中序序列不能为以确定一颗树的原因:对于先序序列,某个根节点右边都是(这个都是并不完全是从他到结尾的意思)他的孩子节点,我们选定他紧挨着右边的这个点,那这个点肯定就是他某个子树(不确定左右)的根节点root2,root2右边的所有点(所有定义同理)我们称为集合S1,然后再去看这个点root2在后序序列中的位置,如果他左边的点的个数与S1完全一样 那我们就无法区分这一些是左子树还是右子树
那么考虑解题思路,由于只要输出其中一个方案,所以假定为左孩子即可
每次都是递归求解当前区间
对于当前的区间,以下范围都局限于当前区间
先序序列第一个点肯定是根节点,然后他右边的点都是他的子节点,我们选定他紧挨着右边的这个点,那这个点肯定就是他某个子树(不确定左右)的根节点root,我们在后序序列中遍历寻找这个根节点root,那么在后序遍历范围0~idx就是左子树的节点,idx+1到r范围内是右子树的节点,但是如果右子树节点数为0,也就是说从root到R的点等于从0到idx的点,我们就无法确定这是左子树还是右子树
剩下的递归建树就好。
这个题只需要边递归边记录中序就可以了。

分享一个跟网上绝大多数博客不太一样的写法

#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<stack>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e2+5;
int pre[maxn],post[maxn];
vector<int> in;
int flag=1,k,n;
void build(int len,int pre[],int post[])
{
	if(len==0)
		return;
	if(len==1)
	{
		in.push_back(pre[0]);
		return;
	}
	int i;
	for(i=0;i<len;i++)
		if(post[i]==pre[1])
			break;
	if(i==len-2)
		flag=0;
	build(i+1,pre+1,post);
	in.push_back(pre[0]);
	build(len-i-2,pre+2+i,post+i+1);
}
int main()
{
	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]);
	build(n,pre,post);
	if(flag)
		printf("Yes\n");
	else printf("No\n");
	for(int i=0;i<n;i++)
		printf("%d%c",in[i]," \n"[i==n-1]);
	return 0;
}

然后自己又写了一发跟网上一样的写法

#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<stack>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e2+5;
int pre[maxn],post[maxn];
vector<int> in;
int flag=1,k,n;
void build(int prel,int prer,int postl,int postr)
{
	if(prel>prer)
		return;
	if(prel==prer)
	{
		in.push_back(pre[prel]);
		return;
	}
	int i;
	for(i=postl;i<=postr;i++)
		if(post[i]==pre[prel+1])
			break;
	int num=i-postl;
	if(prer-prel-1==num)
		flag=0;
	build(prel+1,prel+num+1,postl,i);
	in.push_back(pre[prel]);
	build(prel+num+2,prer,i+1,postr-1);
}
int main()
{
	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]);
	build(0,n-1,0,n-1);
	if(flag)
		printf("Yes\n");
	else printf("No\n");
	for(int i=0;i<n;i++)
		printf("%d%c",in[i]," \n"[i==n-1]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值