题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805440976633856
题目大意
给出n个数,问这n个数有没有可能是一个二叉搜索树或其镜像的先序遍历的结果,二叉搜索树的镜像就是把所有节点的左右子树反转。
分析
先按给出的序列建立一棵二叉搜索树,然后先序遍历这棵二叉搜索树,判断得到的序列与给出的序列是否一致,如果一致,输出后序遍历的结果;如果不一致,再按给出的序列建立一棵二叉搜索树的镜像树,然后再先序遍历,判断得到的序列与给出的序列是否一致,一致的话输出后序遍历的结果,不一致输出NO。
关键是处理镜像问题,二叉搜索树是小于根节点的在左子树上,大于等于根节点的在右子树上,那么在建立镜像二叉搜索树的时候,我们把大于等于根节点的放在左子树上,小于根节点的放在右子树上,先序遍历和后序遍历还按原来的法则操作就可以了。
值得注意的是,这个题不能用数组,因为如果给出的数恰好全部在一个链上,那么必然会越界,所以要用链表。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int n, cnt, d, a[N], ans[N];
struct node {
int data;
node *left, *right;
};
struct node *root = NULL;
void insert_1(node * &root, int w) {
if(root == NULL) {
root = new node();
root->data = w;
root->left = root->right = NULL;
return ;
}
if(w < root->data)
insert_1(root->left, w);
else
insert_1(root->right, w);
}
void insert_2(node * &root, int w) {
if(root == NULL) {
root = new node();
root->data = w;
root->left = root->right = NULL;
return ;
}
if(w >= root->data)
insert_2(root->left, w);
else
insert_2(root->right, w);
}
void preorder(node * &root) {
if(root == NULL) return ;
ans[++cnt] = root->data;
preorder(root->left);
preorder(root->right);
}
void postorder(node * &root) {
if(root == NULL) return ;
postorder(root->left);
postorder(root->right);
if(d > 0) printf(" ");
printf("%d", root->data);
d++;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
insert_1(root, a[i]);
int flag = 1;
cnt = 0;
preorder(root);
for(int i = 1; i <= n; i++) {
if(ans[i] != a[i]) {
flag = 0;
break;
}
}
if(flag) {
d = 0;
printf("YES\n");
postorder(root);
printf("\n");
} else {
root = NULL;
for(int i = 1; i <= n; i++)
insert_2(root, a[i]);
flag = 1;
cnt = 0;
preorder(root);
for(int i = 1; i <= n; i++) {
if(ans[i] != a[i]) {
flag = 0;
break;
}
}
if(!flag) {
printf("NO\n");
} else {
d = 0;
printf("YES\n");
postorder(root);
printf("\n");
}
}
return 0;
}