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;
}