我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805440976633856
题目描述:
题目翻译:
1043 这是一棵二分搜索树吗
一棵二分搜索树是一棵二叉树,递归地定义如下:
左子树的节点都小于当前节点的值。
右子树的节点都大于或等于当前节点的值。
左右子树都是一棵二分搜索树。
如果我们交换左右子树的每一个节点,交换后的树称作二分搜索树的镜像。
现在给你一串正整数序列,你需要指出这是否是一棵二分搜索树的前序遍历或一棵二分搜索树镜像的前序遍历。
输入格式:
每个输入文件包含一个测试用例。在每个测试用例中,第一行给出一个正整数N(<= 1000)。接下来的一行给出N个正整数。一行中的所有数字都由一个空格隔开。
输出格式:
对每个测试用例,如果该序列是一棵二分搜索树的前序遍历或是一棵二分搜索树的镜像的前序遍历,就在第一行中输出YES。否则,输出NO。如果答案是YES,则在下一行输出这棵树的后序遍历。一行中的所有数字都由一个空格隔开,行末不得有多余空格。
输入样例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
知识点:二分搜索树的后序遍历、前序遍历、重建二分搜索树
思路一:根据前序遍历结果重建二分搜索树及其镜像(静态数组实现)
对于普通的二叉树,我们需要中序遍历 + (前序遍历/后序遍历/层序遍历)才能重建该二叉树。因为前序遍历/后序遍历/层序遍历的作用都是提供根节点,而中序遍历的作用是区分左右子树。关于二叉树的重建,可以参考我的另一篇博文:PAT-ADVANCED1020——Tree Traversals,讲的是如何根据二叉树的后序遍历和中序遍历重建该二叉树。
但对于二分搜索树而言,我们只需根据前序遍历/后序遍历/层序遍历就能重建二分搜索树。因为其左右子树的判定是根据节点的值来比较大小定的,我们只需要有根结点的信息即可。自然,我们无法通过二分搜索树的中序遍历来重构它。因为任何二分搜索树的中序遍历结果都是一个递增序列,我们得不到任何根结点的信息。
对于题给的前序遍历结果,我们假定这是一棵二分搜索树的前序遍历结果,将其重建为一棵二分搜索树,再根据其后序遍历结果的节点个数是否等于N来判断题给的序列是否是一棵二分搜索树的前序遍历结果。
同样的做法,我们再将其重建为一棵二分搜索树的镜像,再根据其后序遍历结果的节点个数是否等于N来判断题给的序列是否是一棵二分搜索树的镜像的前序遍历结果。
如果上述两个判断都不满足,则这不是一棵二分搜索树的前序遍历结果,输出"NO"即可。
时间复杂度和空间复杂度均是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node {
int data;
int lchild;
int rchild;
};
int N; //节点个数
int preOrder[1000]; //前序遍历
vector<int> postOrder; //后序遍历结果
node Node[1000];
int index = 0;
int createBinarySearchTree(int leftPre, int rightPre); //根据前序遍历构建二叉搜索树
int createMirrorBinarySearchTree(int leftPre, int rightPre); //根据前序遍历构建镜像二叉搜索树
void postOrderTraversal(int root);
int main() {
cin >> N;
for(int i = 0; i < N; i++) {
cin >> preOrder[i];
}
int root = createBinarySearchTree(0, N - 1);
postOrderTraversal(root);
if(postOrder.size() == N) {
cout << "YES" << endl;
for(int i = 0; i < N; i++) {
cout << postOrder[i];
if(i != N - 1) {
cout << " ";
}
}
cout << endl;
} else {
postOrder.clear();
index = 0;
root = createMirrorBinarySearchTree(0, N - 1);
postOrderTraversal(root);
if(postOrder.size() == N) {
cout << "YES" << endl;
for(int i = 0; i < N; i++) {
cout << postOrder[i];
if(i != N - 1) {
cout << " ";
}
}
cout << endl;
} else {
cout << "NO" << endl;
}
}
return 0;
}
int createBinarySearchTree(int leftPre, int rightPre) {
if(leftPre > rightPre) {
return -1;
}
int root = index++;
Node[root].data = preOrder[leftPre];
int k;
for(k = leftPre + 1; k <= rightPre; k++) {
if(preOrder[k] >= preOrder[leftPre]) {
break;
}
}
int l;
for(l = k; l <= rightPre; l++) {
if(preOrder[l] < preOrder[leftPre]) {
break;
}
}
Node[root].lchild = createBinarySearchTree(leftPre + 1, k - 1);
Node[root].rchild = createBinarySearchTree(k, l - 1);
return root;
}
int createMirrorBinarySearchTree(int leftPre, int rightPre) {
if(leftPre > rightPre) {
return -1;
}
int root = index++;
Node[root].data = preOrder[leftPre];
int k;
for(k = leftPre + 1; k <= rightPre; k++) {
if(preOrder[k] < preOrder[leftPre]) {
break;
}
}
int l;
for(l = k; l <= rightPre; l++) {
if(preOrder[l] >= preOrder[leftPre]) {
break;
}
}
Node[root].lchild = createMirrorBinarySearchTree(leftPre + 1, k - 1);
Node[root].rchild = createMirrorBinarySearchTree(k, l - 1);
return root;
}
void postOrderTraversal(int root) {
if(root == -1) {
return;
}
postOrderTraversal(Node[root].lchild);
postOrderTraversal(Node[root].rchild);
postOrder.push_back(Node[root].data);
}
C++解题报告:
思路二:根据插入顺序重建出二分搜索树(静态数组实现)
这个思路基于这样一个事实,给定一棵二分搜索树的前序序列。按照该序列向一棵空的二分搜索树中依次添加元素,所得到的二分搜索树的前序序列一定和给定的前序序列相同。这其实很好理解,因为前序序列先访问的根结点,再访问的左右子树,而我们构建二分搜索树时,也是先构建出根节点,再往根节点中依次添加节点。
对于这样构建出的二分搜索树,即使给定的是二分搜索树的镜像的前序序列,也一定是一棵二分搜索树而不会是其镜像。对于镜像的判断,我们需要在遍历这棵二分搜索树的时候交换左右子树的遍历顺序。同理,在求后序遍历的时候也需要交换左右子树的遍历顺序。
时间复杂度和空间复杂度均是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node {
int data;
int lchild;
int rchild;
};
int N; //节点个数
vector<int> preOrder; //前序遍历
node Node[1000];
int index = 0;
vector<int> preOrderBSTree;
vector<int> preOrderBSTreeMirror;
vector<int> postOrderBSTree;
vector<int> postOrderBSTreeMirror;
int newNode(int v); //分配一个Node数组中的节点给新节点,index为其下标
void insert(int &root, int x); //插入,root为根节点在数组中的下标,要加引用
int createBinarySearchTree(); //根据输入的前序遍历构建二分搜索树
void preOrderTraversal(int root); //二叉搜索树前序遍历
void preOrderTraversalMirror(int root); //镜像二叉搜索树前序遍历
void postOrderTraversal(int root); //二叉搜索树后序遍历
void postOrderTraversalMirror(int root); //镜像二叉搜索树后序遍历
int main() {
cin >> N;
int input;
for(int i = 0; i < N; i++) {
cin >> input;
preOrder.push_back(input);
}
int root = createBinarySearchTree();
preOrderTraversal(root);
preOrderTraversalMirror(root);
postOrderTraversal(root);
postOrderTraversalMirror(root);
if(preOrder == preOrderBSTree){
cout << "YES" << endl;
for(int i = 0; i < postOrderBSTree.size(); i++){
cout << postOrderBSTree[i];
if(i != postOrderBSTree.size() - 1){
cout << " ";
}
}
}else if(preOrder == preOrderBSTreeMirror){
cout << "YES" << endl;
for(int i = 0; i < postOrderBSTreeMirror.size(); i++){
cout << postOrderBSTreeMirror[i];
if(i != postOrderBSTreeMirror.size() - 1){
cout << " ";
}
}
}else{
cout << "NO" << endl;
}
return 0;
}
int newNode(int v) {
Node[index].data = v;
Node[index].lchild = -1;
Node[index].rchild = -1;
return index++;
}
void insert(int &root, int x) {
if(root == -1) {
root = newNode(x);
return;
}
if(x < Node[root].data) {
insert(Node[root].lchild, x);
} else {
insert(Node[root].rchild, x);
}
}
int createBinarySearchTree() {
int root = -1; //新建根结点
for(int i = 0; i < N; i++) {
insert(root, preOrder[i]);
}
return root;
}
void preOrderTraversal(int root) {
if(root == -1) {
return;
}
preOrderBSTree.push_back(Node[root].data);
preOrderTraversal(Node[root].lchild);
preOrderTraversal(Node[root].rchild);
}
void preOrderTraversalMirror(int root) {
if(root == -1) {
return;
}
preOrderBSTreeMirror.push_back(Node[root].data);
preOrderTraversalMirror(Node[root].rchild);
preOrderTraversalMirror(Node[root].lchild);
}
void postOrderTraversal(int root) {
if(root == -1) {
return;
}
postOrderTraversal(Node[root].lchild);
postOrderTraversal(Node[root].rchild);
postOrderBSTree.push_back(Node[root].data);
}
void postOrderTraversalMirror(int root) {
if(root == -1) {
return;
}
postOrderTraversalMirror(Node[root].rchild);
postOrderTraversalMirror(Node[root].lchild);
postOrderBSTreeMirror.push_back(Node[root].data);
}
C++解题报告:
思路三:根据插入顺序重建出二分搜索树(指针实现)
时间复杂度和空间复杂度均是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node {
int data;
node* lchild;
node* rchild;
};
int N; //节点个数
vector<int> preOrder; //前序遍历
vector<int> preOrderBSTree;
vector<int> preOrderBSTreeMirror;
vector<int> postOrderBSTree;
vector<int> postOrderBSTreeMirror;
node* newNode(int v); //分配一个Node数组中的节点给新节点,index为其下标
void insert(node* &root, int x); //插入,root为根节点在数组中的下标,要加引用
node* createBinarySearchTree(); //根据输入的前序遍历构建二分搜索树
void preOrderTraversal(node* root); //二叉搜索树前序遍历
void preOrderTraversalMirror(node* root); //镜像二叉搜索树前序遍历
void postOrderTraversal(node* root); //二叉搜索树后序遍历
void postOrderTraversalMirror(node* root); //镜像二叉搜索树后序遍历
int main() {
cin >> N;
int input;
for(int i = 0; i < N; i++) {
cin >> input;
preOrder.push_back(input);
}
node* root = createBinarySearchTree();
preOrderTraversal(root);
preOrderTraversalMirror(root);
postOrderTraversal(root);
postOrderTraversalMirror(root);
if(preOrder == preOrderBSTree){
cout << "YES" << endl;
for(int i = 0; i < postOrderBSTree.size(); i++){
cout << postOrderBSTree[i];
if(i != postOrderBSTree.size() - 1){
cout << " ";
}
}
}else if(preOrder == preOrderBSTreeMirror){
cout << "YES" << endl;
for(int i = 0; i < postOrderBSTreeMirror.size(); i++){
cout << postOrderBSTreeMirror[i];
if(i != postOrderBSTreeMirror.size() - 1){
cout << " ";
}
}
}else{
cout << "NO" << endl;
}
return 0;
}
node* newNode(int v) {
node* root = new node;
root->data = v;
root->lchild = NULL;
root->rchild = NULL;
return root;
}
void insert(node* &root, int x) {
if(root == NULL) {
root = newNode(x);
return;
}
if(x < root->data) {
insert(root->lchild, x);
} else {
insert(root->rchild, x);
}
}
node* createBinarySearchTree() {
node* root = NULL; //新建根结点
for(int i = 0; i < N; i++) {
insert(root, preOrder[i]);
}
return root;
}
void preOrderTraversal(node* root) {
if(root == NULL) {
return;
}
preOrderBSTree.push_back(root->data);
preOrderTraversal(root->lchild);
preOrderTraversal(root->rchild);
}
void preOrderTraversalMirror(node* root) {
if(root == NULL) {
return;
}
preOrderBSTreeMirror.push_back(root->data);
preOrderTraversalMirror(root->rchild);
preOrderTraversalMirror(root->lchild);
}
void postOrderTraversal(node* root) {
if(root == NULL) {
return;
}
postOrderTraversal(root->lchild);
postOrderTraversal(root->rchild);
postOrderBSTree.push_back(root->data);
}
void postOrderTraversalMirror(node* root) {
if(root == NULL) {
return;
}
postOrderTraversalMirror(root->rchild);
postOrderTraversalMirror(root->lchild);
postOrderBSTreeMirror.push_back(root->data);
}
C++解题报告: