pat 团体天梯赛 L2-004. 这是二叉搜索树吗?
L2-004. 这是二叉搜索树吗?
时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,
- 其左子树中所有结点的键值小于该结点的键值;
- 其右子树中所有结点的键值大于等于该结点的键值;
- 其左右子树都是二叉搜索树。
所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。
给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。
输入格式:
输入的第一行给出正整数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
思路:搜索二叉树的重建,告诉你了前序遍历,那么可以进行递归的找出后序遍历。前序遍历的特性可知,每次递归的查找区间[l,r]的根以及其左右子树,节点l处的值一定是根,因为前序遍历总是先确定出根,之后再去搜索其左子树和右子树。
那么左子树和右子树的范围应当如何确定呢?首先左右子树当中所有的元素的编号应当在[l+1,r]中,并且由搜索树的性质,在根的左子树上的值都小于根,右子树上的值大于等于根,那么容易确定出左右子树了。
之后模拟后续遍历:即先递归搜素左右子树,之后再输出当前节点处的值。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<cmath> #include<map> #include<set> using namespace std; #define INF 0x3f3f3f3f #define EPS 1e-5 #define pi cos(-1) const int N_MAX = 1000+ 15; int n,pos; bool is_mirror; vector<int>pre,post; void dfs(const int& l, const int& r) {//找出[l,r]区间范围的根以及其左右子树 if (l > r)return; int root = pre[pos++]; int i = l + 1, j = r; if (!is_mirror) {//不是镜像,左子树上的值要比root小,右子树上的值大于等于root while (i <= r&&root>pre[i])i++; while (j>l&&root <= pre[j])j--; } else { while (i <= r&&root <= pre[i])i++; while (j >l&&root> pre[j])j--; } if (i - j != 1)return;//如果不是搜索树不满足条件 dfs(l + 1, j); dfs(i, r); post.push_back(root); } int main() { scanf("%d", &n); pre.resize(n); for (int i = 0; i < n;i++) { scanf("%d",&pre[i]); } pos = 0; is_mirror = 0; dfs(0, n-1); if (post.size()!=n) { pos = 0; post.clear(); is_mirror = 1; dfs(0, n-1); } if (post.size() == n) { puts("YES"); for (int i = 0; i <n;i++) { cout << post[i]; if (i + 1 == n)cout << endl; else cout << " "; } } else { puts("NO"); } pre.clear(); return 0; }
如果知道后序遍历,让你判断是否是搜索树,如果是,输出前序遍历,方法也类似,贴一下代码:
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<vector> #include<string> #include<iomanip> #include<map> #include<stack> #include<set> #include<queue> #include<sstream> using namespace std; #define N_MAX 100000+2 #define INF 0x3f3f3f3f struct Node { int key=INF, left, right; Node() {} Node(int key,int left,int right):key(key),left(left),right(right) {} }node[N_MAX]; int n,cnt=n-1; vector<int>pre,post; bool ok = 1; void dfs(int n, int l, int r, bool is_mirror) { if (l > r)return; int root = post[cnt--]; int i = l, j = r-1; if (!is_mirror) { while (i < r&&post[i] <root) i++; while (j >= l&&post[j] >= root)j--; } else { while (i < r&&post[i] >= root) i++; while (j >= l&&post[j] < root)j--; } if (i - j != 1) { ok = 0; return; } node[n] = Node(root, 2 * n + 1, 2 * n + 2); dfs(2*n+2,i, r-1,is_mirror); dfs(2*n+1,l, j,is_mirror);//!!! } void preorder(int n) { pre.push_back(node[n].key); if (node[2*n+1].key != INF)preorder(node[n].left); if (node[2*n+2].key != INF)preorder(node[n].right); } int main() { while (cin >> n) { post.resize(n); for (int i = 0; i < n; i++)cin >> post[i]; ok = 1; cnt = n-1; dfs(0,0, n - 1, 0); if (!ok) { ok = 1; cnt = n-1; dfs(0,0, n - 1, 1); if (!ok) { puts("NO"); } } if (ok) { preorder(0); puts("YES"); for (int i = 0; i < pre.size(); i++) printf("%d%c", pre[i], i + 1 == pre.size() ? '\n' : ' '); } } return 0; }