CCCC团体程序设计天梯赛 L2-004 这是二叉搜索树吗?

记录天梯赛题目合集 跳转查看

题目链接

题目描述

一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,

  • 其左子树中所有结点的键值小于该结点的键值;
  • 其右子树中所有结点的键值大于等于该结点的键值;
  • 其左右子树都是二叉搜索树。
    所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。

给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。

输入格式
输入的第一行给出正整数 \(N(≤1000)\)。随后一行给出 \(N\) 个整数键值,其间以空格分隔。

输出格式
如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 \(YES\) ,然后在下一行输出该树后序遍历的结果。数字间有 \(1\) 个空格,一行的首尾不得有多余空格。若答案是否,则输出 \(NO\)

输入样例 1

7
8 6 5 7 10 8 11

输出样例 1

YES
5 7 6 8 11 10 8

输入样例 2

7
8 10 11 8 6 7 5

输出样例 2

YES
11 8 10 7 5 6 8

输入样例 3

7
8 6 8 5 10 9 11

输出样例 3

NO

题目分析

首先,在解决该题前,需要了解什么是树的前序遍历、后序遍历。对于二叉树的前序遍历,就是按 根节点、左子树、右子树的顺序逐步遍历树,后序遍历就是按 左子树、右子树、根节点的顺序逐步遍历树。

题目给出的二叉树的前序遍历,那么根据前序遍历的规定,可以知道第一个一定是根节点,接下来就是左子树的所有结点,最后是右子树的所有结点。因为要满足二叉搜索树的性质,左子树所有键值小于根节点键值,右子树所有键值大于等于根节点键值,所以紧跟的结点应该会小于根节点键值,如果是大于等于根节点键值,那么就是二叉树进行了镜像。所以,我们根据根节点的键值,可以让接下来连续一段键值小于根节点键值,最后一段键值大于等于根节点键值(镜像则相反)。

理清楚规律后,我们思考如何进行编码。可以使用双指针指向每棵子树的首尾结点,先不考虑镜像,那么接下来连续一段都应该小于根节点键值,余下的都应该大于等于根节点键值,用两个指针通过遍历完成指向:左指针从首结点向后遍历,右指针从尾结点向前遍历,如果左指针刚好在右指针的右边一个结点那么就是符合的,否则就不是二叉搜索树的前序遍历结果,具体看代码吧。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <unordered_map>

using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const ll inf = 1e18;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;

int n;
int p[N];
bool flag;
vector<int> res;

void dfs(int l, int r)
{
	if (l > r) return ;
	int tl = l + 1, tr = r;
    // 如果没有镜像
	if (!flag) {
        // 左指针向后遍历满足小于根节点键值,右指针向前遍历满足大于等于根节点键值
		while (tl <= r && p[tl] < p[l]) tl ++;
		while (tr > l && p[tr] >= p[l]) tr --;
	}
	else {
		while (tl <= r && p[tl] >= p[l]) tl ++;
		while (tr > l && p[tr] < p[l]) tr --;
	}
	
    // 如果左指针不是刚好右指针的右边,那么就不是二叉搜索树
	if (tl - tr != 1) return ;
	dfs(l + 1, tr);
	dfs(tl, r);
    // 因为后序遍历刚好是前序遍历的相反操作,只需让根节点最后放入就变为后序遍历
	res.emplace_back(p[l]);
}

void solve()
{
	cin >> n;
	for (int i = 0; i < n; i ++) cin >> p[i];

    // 如果第二个结点的键值大于第一个结点,那么就可能是镜像
    if (p[1] >= p[0]) flag = 1;
	dfs(0, n - 1);
	
    // 存储的后序遍历节点个数不足n,说明这不是二叉搜索树的前序遍历
	if (res.size() != n) cout << "NO";
	else {
		cout << "YES" << '\n';
		for (int i = 0; i < res.size(); i ++) {
			if (i) cout << ' ';
			cout << res[i];
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	
	int T = 1;
//	cin >> T;
	while (T --) solve();
	return 0;
}
posted @ 2025-03-25 19:38  Natural_TLP  阅读(48)  评论(0)    收藏  举报