一遍搞定!关于如何已知后序和中序序列得到前序序列的问题

首先来个具体的问题吧,因为只是空谈显示不出效果。

如题


求先序排列

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度<=8)。
输入格式
  两行,每行一个字符串,分别表示中序和后序排列
输出格式
  一个字符串,表示所求先序排列

样例输入
  BEADC
  EBDCA
样例输出
ABECD

解题思路

关于这题其实解体思路很多,但是目前我发现最简单的只有一种。

先从一种最常规的解法思路说起吧,不要心急,这种解法与最简解法也是思路相近的。

对于这题,我们知道它的先序和中序序列,以题目中的样例为例,我们可以很容易的通过后序找到它的根节点A,并且由中序序列得知B、E是A的左子树内容,D、C是A的右子树内容。

那么要得到想要的先序序列,就必须继续确定左右子树的根节点,很显然这是一个递归逻辑。
停止递归的条件是左右子树的节点全部输出。

确定根节点,最简单的一种思路就是用for循环来查找,比如我们确定了A的左子树,有B,E两个节点,然后我们要查找左子树的根节点,只需要找到左子树在后序序列中最靠右的元素就好啦。

写起来就两个for循环,一个用来遍历后序数组,一个用来挨个判断是否是左子树的节点。然后用个变量存储根节点。

这样就可以不断的用递归思路求解根节点,然后输出,直至左右子树与根节点重合,结束。

代码如下:

#include <iostream>
#include <string>

using namespace std;

string s1, s2;

void dfs(int l1, int r1, int l2, int r2)
{
	cout << s1[r1+1];
	if (r1 >=l1)
	{
		int poi = 0;
		for (int i = 0; i < s2.length(); i++)
		{
			for (int j = l1; j <=r1; j++)
			{
				if (s2[i] == s1[j])
				{
					poi = j;
					break;
				}
			}
		}
		dfs(l1, poi-1, poi+1, r1);
	}
	 if(r2>=l2)
	{
		int poi = 0;
		for (int i = 0; i < s2.length(); i++)
		{
			for (int j = l2; j <=r2; j++)
			{
				if (s2[i] == s1[j])
				{
					poi = j;
					break;
				}
			}
		}
		dfs(l2, poi-1, poi + 1, r2);
	}
}

int main()
{
	cin >> s1 >> s2;

	int ma = s1.length() - 1;
	int d = s1.find(s2[ma]);
	dfs(0, d-1, d+1, ma);

	return 0;
}

接下来的,是一种更优的算法,我们已经知道了求解先序序列的基本思路。
但是,如果使用上面的方法,时间复杂度为(nlogn)。
中间的for循环查找会造成大量的时间浪费,因为仔细研究后序序列和中序序列,他们是可以找到一些规律的。
先给出下图
中序与后续序列的规律
仔细看的话(看图就好,下面可以忽略)可以发现,后序遍历中根节点排布是有一定规律的。
后序序列中最靠右的节点就是子树的根节点。

我们之前使用的方法是从前面一个一个查找,但是其实如果我们假设中序和后序序列的左端和右段下标分别为了l1,r1,l2,r2,并且中序遍历根节点位置为poi。

我们就可以轻松地得到它的左子树以及右子树的根节点位置,而且还有两种表示方法,一种是从左边考虑,另一种从右边考虑。

比如表示后序序列左子树的根节点的位置,可以是l2+(poi-l1)-1,也可以是r2-(r1-poi)-1.

那么写出来的代码当然也可以是两种,不过思路其实相同就是。

参考代码:

#include <iostream>
#include <string>

using namespace std;

string s1, s2;

void dfs(int l1, int r1, int l2, int r2)
{
	cout << s2[r2];//后序序列找到的根节点
	int d = s1.find(s2[r2]);
	if (d > l1)
	{
		dfs(l1, d - 1, l2, l2+(d-l1)-1);
	}
	if (d < r1)
	{
		dfs(d + 1, r1, r2-(r1-d), r2 - 1);
	}
}

int main()
{
	cin >> s1 >> s2;

	int ma = s1.length() - 1;
	dfs(0, ma, 0, ma);

	return 0;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值