1138 Postorder Traversal (25分)/DFS+剪枝

问题描述

在这里插入图片描述

题目大意

根据二叉树的先序遍历序列和中序遍历序列输出后序遍历的第一个数。

解析

刚开始误以为后序遍历的第一个数一定是树的第一个左叶子结点,但是有可能第一个叶子结点是右结点,这时后序遍历的第一个结点就是它。因此问题就是找第一个叶子结点的问题。由于对直接求后序序列的算法很熟练,直接求了整个后序序列。时间上很险,时间限制是650ms,所以这个算法很悬。
在这里插入图片描述
那么其实可以在找到第一个叶子结点之后就对其他子树进行剪枝…即在递归过程中,当找到第一个叶结点之后就不再进入其他递归路径,原路返回即可。

#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int pre[50000], in[50000];
bool flag = 0;
void solution(int preL, int preR, int inL, int inR) {
	if (preL>preR||flag) { //flag==true表示已经找到第一个叶子结点
		return;
	}
	int k;
	for (k = inL; k <= inR && pre[preL] != in[k]; k++);
	int numL = k - inL;
	solution(preL + 1, preL + numL, inL, k - 1);
	solution(preL + numL + 1, preR, k + 1, inR);
	if (flag == 0) { //还没有找到第一个叶结点
		printf("%d", pre[preL]);
		flag = 1;
	}
}
int main() {
#ifdef ONLINE_JUDGE
#else
	freopen("1.txt", "r", stdin);
#endif
	int n; cin >> n;
	for (int i = 0; i < n; i++) scanf("%d", &pre[i]);
	for (int i = 0; i < n; i++) scanf("%d", &in[i]);
	solution(0, n - 1, 0, n - 1);
	return 0;
}

可以发现,第4个测试点仍然是600+ms,推测该测试点的第一个叶结点位于树的最右侧,还是需要递归完所有路径。不过对于普遍的情况,这个算法还是更高效一些。
在这里插入图片描述

发布了103 篇原创文章 · 获赞 9 · 访问量 4705

猜你喜欢

转载自blog.csdn.net/weixin_43590232/article/details/104380378
今日推荐