题目

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
  • Both the left and right subtrees must also be binary search trees.

If we swap the left and right subtrees of every node, then the resulting tree is called the Mirror Image of a BST.

Now given a sequence of integer keys, you are supposed to tell if it is the preorder traversal sequence of a BST or the mirror image of a BST.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first print in a line YES if the sequence is the preorder traversal sequence of a BST or the mirror image of a BST, or NO if not. Then if the answer is YES, print in the next line the postorder traversal sequence of that tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

7

8 6 5 7 10 8 11

Sample Output 1:

YES

5 7 6 8 11 10 8

Sample Input 2:

7

8 10 11 8 6 7 5

Sample Output 2:

YES

11 8 10 7 5 6 8

Sample Input 3:

7

8 6 8 5 10 9 11

Sample Output 3:

NO

题目解读

给定一个输入序列,判断它是否是一棵二叉搜索树或其镜像树的前序遍历序列,如果是,输出 YES 以及它的后序遍历序列;如果不是,输出 NO。

二叉搜索树的定义:

  • 左子树所有节点的键值小于根节点
  • 右子树所有节点的键值大于等于根有点
  • 左子树和右子树也必须是二叉搜索树(满足上面两点)

镜像树:交换原二叉搜索树每个节点的左右子树。所以它满足:

  • 左子树所有节点的键值大于等于根节点
  • 右子树所有节点的键值小于根有点
  • 左子树和右子树也必须满足上面两点

首先我们应该明白一个道理:

一般情况下,我们要根据一棵二叉树的前序遍历结果和中序遍历结果才能得到它的后序遍历结果,但这里为什么只需要前序遍历结果就可以得到后序遍历结果?

二叉搜索树又叫二叉排序树,由它的定义就知道它本身是有序的,对一棵二叉搜索树进行中序遍历,得到就是一个非降序有序序列,这也可以作为一种排序方法。

所以如果给出的序列的确是一棵二叉搜索树的前序遍历的话,对它进行一次排序就能得到它的中序遍历结果,前序+中序就能得到后序,所以需要明白这个隐含条件。

思路分析

你可以选择用给出的输入构造出一棵二叉搜索树,然后再对这棵树进行前序遍历,判断得到的结果是否和输入一致,如果不一致,那就输出 NO,如果一致就输出这这棵树的后序遍历结果。

我这里参考了柳神的代码,采用了一种更为简单的方法。

可以想象一下,根据 前序遍历结果和中序遍历结果能得到正确的后序遍历结果,那,如果给出的前序结果是错误的呢(它不是一棵二叉搜索树的前序结果),那肯定不能得到正确的后序遍历结果,假如我用一个vector来保存在此过程中得到的节点序列,那么最终这个vector中的节点个数肯定不够原来输入的个数(当然前提是算法正确)。

所以我们可以假设这个输入序列是对的,然后利用这个输入序列去得到后序序列并保存,如果最终得到的结果中节点个数不够,那说明它不是正确的前序遍历,否则就直接输出得到的结果

当然这里还多了一步,如果把它当作前序遍历序列不能得到正确结果,我们还要把它当作二叉搜索树的镜像树的前序结果再执行一次这个过程,如果这次还不能得到正确结果,那说明它的确是错误的前序序列。

接下来我们来研究一下这个算法怎么写:

对于一棵二叉搜索树,因为它的有序性,对他进行前序遍历(根,左子树,右子树),得到的序列肯定满足这个样子:根节点 所有比它小的节点 所有比它的大的节点

比如下面这棵二叉搜索树



它的前序遍历结果是 8 567 91011,是不是很有特点,我们能根据这个很好的划分出它的左右子树:

  • 当前树根是8,设置左指针i,初始是8的下一个位置,右指针j,初始是当前树最后一个有效位置
  • i从左往右,扫描前序序列,遇到比根小的就i++,会停在9的位置;
  • j从右往左,扫描前序序列,遇到比根大于或等于的就j--,最后会停在7的位置
  • 这样一次扫描后,应该满足 j + 1 == i,对于每一个二叉搜索树的前序遍历都应该满足这个特点,所以这里可以作为函数的一个出口,不满足,就退出
  • 划分成左右两部分后,因为我们要得到后序遍历(左,右,中),所以对做左子树进行这个处理,对右子树进行这个处理,把当前树根加入vector,注意顺序不能乱!

从上面可以看出:

  • 这个函数需要两个参数,一个是当前树的根,一个是当前树最后一个节点在前序序列中的位置
  • 每次双指针扫描结束后,不满足 i == j + 1 就退出
  • 最小的子树是只有一个节点,此时这两个参数应该相等,所以函数刚进来的时候,判断一个,如果根的位置 > 最后一个有效位置,就直接退出。

上面的过程是针对于 把输入序列当作二叉搜索树的前序遍历进行的,如果要把输入序列当作镜像树的前序遍历序列呢?很简单,根据对称性,只需要把 i 和 j 的扫描时的判断条件取个反就行了,也就是 > 变成 <=> 变成 <=.

所以你可以写成两个函数分别处理这两种情况,也可以设置一个标志在函数内部分情况,我选择第二种,直接看代码很清楚。

综上,总体执行流程为:

  • 把输入序列当作二叉搜索树前序遍历,执行这个函数,得到后序结果,
  • 如果所得结果中节点个数与输入一致,直接输出
  • 如果不一致,把输入序列当作二叉搜索树镜像树的前序遍历,也就是改变标志位,再执行一次这个函数,得到后序结果
  • 再判断所得结果中节点个数是否与输入一致,一致则输出,不一致则输出 NO。

完整代码

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. // 前序遍历序列,后序遍历序列
  5. vector<int> pre, post;
  6. // 是否当作二叉搜索树的镜像树处理
  7. bool ismirror = false;
  8. // 当前处理的树的根节点在前序序列中的下标
  9. // 当前处理的树最后一个节点在前序序列中的有效位置
  10. void GetPost(int root, int tail) {
  11. // 最小的树就一个节点,root=tail
  12. if (root > tail) return;
  13. int i = root + 1, j = tail;
  14. // 当作二叉搜索树树处理
  15. if (!ismirror) {
  16. // 左孩子都小于根
  17. while (i <= tail && pre[i] < pre[root]) i++;
  18. // 右孩子都大于等于根
  19. while (j > root && pre[root] <= pre[j]) j--;
  20. // 当作二叉搜索树的镜像树处理
  21. } else {
  22. // 左孩子都大于等于根
  23. while (i <= tail && pre[i] >= pre[root]) i++;
  24. // 右孩子都小于根
  25. while (j > root && pre[root] > pre[j]) j--;
  26. }
  27. // 不满足二叉搜索树前序遍历结果特点
  28. if (i != j + 1) return;
  29. // 对左子树执行此操作
  30. GetPost(root + 1, j);
  31. // 对右子树执行此操作
  32. GetPost(i, tail);
  33. // 保存当前根
  34. post.push_back(pre[root]);
  35. }
  36. int main() {
  37. int n;
  38. cin >> n;
  39. pre.resize(n);
  40. for (int i = 0; i < n; ++i) cin >> pre[i];
  41. // 当作前序遍历结果,尝试得到后序结果
  42. GetPost(0, n - 1);
  43. // 所得结果节点个数错误
  44. if (post.size() != n) {
  45. // 改变标志位
  46. ismirror = true;
  47. post.clear();
  48. // 当作镜像树前序遍历结果,尝试获取后序结果
  49. GetPost(0, n - 1);
  50. }
  51. // 所得结果正确
  52. if (post.size() == n) {
  53. cout << "YES" << endl;
  54. cout << post[0];
  55. for (int i = 1; i < n; ++i) cout << " " << post[i];
  56. // 所得结果依然错误
  57. } else {
  58. cout << "NO";
  59. }
  60. return 0;
  61. }

PAT 1043 Is It a Binary Search Tree (25分) 由前序遍历得到二叉搜索树的后序遍历的更多相关文章

  1. PAT 甲级 1043 Is It a Binary Search Tree (25 分)(链表建树前序后序遍历)*不会用链表建树 *看不懂题

    1043 Is It a Binary Search Tree (25 分)   A Binary Search Tree (BST) is recursively defined as a bina ...

  2. 1043 Is It a Binary Search Tree (25分)(树的插入)

    A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...

  3. convert sorted list to binary search tree(将有序链表转成平衡二叉搜索树)

    Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...

  4. [LeetCode] Convert Binary Search Tree to Sorted Doubly Linked List 将二叉搜索树转为有序双向链表

    Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers ...

  5. 【PAT甲级】1043 Is It a Binary Search Tree (25 分)(判断是否为BST的先序遍历并输出后序遍历)

    题意: 输入一个正整数N(<=1000),接下来输入N个点的序号.如果刚才输入的序列是一颗二叉搜索树或它的镜像(中心翻转180°)的先序遍历,那么输出YES并输出它的后序遍历,否则输出NO. t ...

  6. Convert Sorted Array to Binary Search Tree(将一个有序数组转换成一颗二叉搜索树)

    Given an array where elements are sorted in ascending order, convert it to a height balanced BST. Fo ...

  7. PAT甲级:1064 Complete Binary Search Tree (30分)

    PAT甲级:1064 Complete Binary Search Tree (30分) 题干 A Binary Search Tree (BST) is recursively defined as ...

  8. PAT 1043 Is It a Binary Search Tree[二叉树][难]

    1043 Is It a Binary Search Tree(25 分) A Binary Search Tree (BST) is recursively defined as a binary ...

  9. PAT Advanced 1043 Is It a Binary Search Tree (25) [⼆叉查找树BST]

    题目 A Binary Search Tree (BST) is recursively defined as a binary tree which has the following proper ...

随机推荐

  1. 09-Python之路---函数进阶

    Python之路---函数进阶️ 程序员三大美德: 懒惰 因为一直致力于减少工作的总工作量. 缺乏耐性 因为一旦让你去做本该计算机完成的事,你将会怒不可遏. 傲慢 因为被荣誉感冲晕头的你会把程序写得让 ...

  2. tableView reloadData页面跳动问题

    参考:https://www.jianshu.com/p/5f033fdd4ddb 一般情况下 if (@available(iOS 11.0, *)) { self.estimatedRowHeig ...

  3. 【数据分析入门】之Spyder中如何让图表单独显示出来

    一般图表只显示在ipython console中,且是静态,无法进行放大,移动等操作解决方案:[win]tools——preferences——ipython console——graphics中ba ...

  4. DOM变化后事件绑定失效

    第一个file在change时,是能够触发事件的,而第二插入的file则没有change事件.对于这个问题,有如下两种解决方法: 第一种是将绑定change事件封装成一个函数,在点击button按钮插 ...

  5. 【Ubuntu】安装Ubuntu18.04.2LTS

    环境:win10专业版.联想30D9主板 ubuntu:18.04.2LTS:Ubuntu镜像传送门:https://ubuntu.com/download/desktop 有两块硬盘,win10安装 ...

  6. Java中的集合(十三) 实现Map接口的Hashtable

    Java中的集合(十三) 实现Map接口的Hashtable 一.Hashtable简介 和HashMap一样,Hashtable采用“拉链法”实现一个哈希表,它存储的内容是键值对(key-value ...

  7. HttpSession之表单的重复提交 & 验证码

    如果采用 HttpServletResponse.sendRedirct() 方法将客户端重定向到成功页面,将不会出现重复提交问题 1.表单的重复提交 1). 重复提交的情况: ①. 在表单提交到一个 ...

  8. Unity 离线建造系统

    很多游戏,特别是养成类手游,都会有自己独特的建造系统,一个建造装置的状态循环或者说生命周期一般是这样的: 1.准备建造,设置各项资源的投入等 2.等待一段倒计时,正在建造中 3.建造结束,选择是否收取 ...

  9. 设计MyTime类 代码参考

    #include <iostream> #include <cstdio> using namespace std; class MyTime { private: int h ...

  10. AVIRIS 简介

    AVIRIS 是指 机载可见光近红外成像光谱(Airborne Visible InfraRed Imaging Spectrometer).是由美国NASA下属的喷气动力实验室(JPL)开发和维护的 ...