团体程序设计天梯赛-练习集——L2-004 这是二叉搜索树吗? (25 分)

对于二叉搜索树,我们规定任一结点的左子树仅包含严格小于该结点的键值,而其右子树包含大于或等于该结点的键值。如果我们交换每个节点的左子树和右子树,得到的树叫做镜像二叉搜索树。

现在我们给出一个整数键值序列,请编写程序判断该序列是否为某棵二叉搜索树或某镜像二叉搜索树的前序遍历序列,如果是,则输出对应二叉树的后序遍历序列。

输入格式:
输入的第一行包含一个正整数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 6 8 5 10 9 11

输出样例2:

NO

思路
这题HBU训练营时候做过,那时候树都不太熟悉,直接百度的,当时这题思路都没看懂
现在懂了,真是震惊于人类的思想,感觉有些东西就像数学一样

初看这题肯定是觉得要建立一个递归,
1.确定该树为二叉搜索树还是镜像二叉搜索树
2.找出左右子树分界点,
(1)二叉搜索树为例,分界点之后的右子树元素都应大于等于原根节点,否则返回false

8 6 5 7 10 8 11

找出左右子树分界点,即为第一个大于等于根节点元素的点10,for循环判断8、11是否大于等于根节点8
(2)镜像二叉树,左子树大于等于根节点,右子树小于根节点。
所有元素*-1,左子树元素小于等于根节点,右子树大于根节点,第一个大于根节点的元素为分界点
3.运用递归判断左子树和右子树是否符合第二条

代码1

#include<bits/stdc++.h>
using namespace std;
int xx[1001];
int flag=1;
bool f=false;
bool dfs(int start,int end){
	if(start>=end) return true;
	int i;
	for(i=start+1;i<end;i++){
		if(flag==1&&xx[i]>=xx[start]||flag==-1&&xx[i]>xx[start]) break;//二叉搜索树找到左右子树分界点
	
	}
	for(int j=i;j<end;j++) if(xx[j]<xx[start]) return false;
	//二叉搜索树,右子树有小于根节点的 flase
	return dfs(start+1,i)&&(i,end);
	//左子树				//右子树 
}
void post(int start,int end){
	if(start>=end) return;
	int i;
	for(i=start+1;i<end;i++){
		if(flag==1&&xx[i]>=xx[start]||flag==-1&&xx[i]>xx[start]) break;
		
	}
	post(start+1,i); post(i,end);
	if(f) cout<<" ";
	cout<<xx[start]*flag; 
	f=true;
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>xx[i];
	if(n>=2&&xx[2]>xx[1]){//此树为镜像二叉搜索树 
		for(int i=0;i<n;i++) xx[i]=xx[i]*-1;//使镜像节点均为负数 
		flag=-1;
		
	}
	if(!dfs(0,n)) cout<<"NO"<<endl;
	else{
		cout<<"YES"<<endl;
		post(0,n);
	}
	return 0;
}

代码2

#include <bits/stdc++.h>
using namespace std;
typedef struct stu* Tree;
struct stu{
	int data;
	Tree left;
	Tree right;
};
int xx[1001];
int flag1=1,flag2=1;
vector<int> post;
void fun(Tree T){
	if(T){
		fun(T->left);
		fun(T->right);
		post.push_back(T->data);
	}
}
Tree setTree(int start,int end){
	Tree T=new stu;
	if(start>end) return NULL;
	T->data=xx[start];
	int i;
	for(i=start+1;i<=end;i++){
		if(xx[i]>=xx[start]) break;
	}
	for(int j=i;j<=end;j++){
		if(xx[j]<xx[start]) flag1=0;
	}
	T->left=setTree(start+1,i-1);
	T->right=setTree(i,end);
	return T;
}
Tree setMirrorTree(int start,int end){
	Tree T=new stu;
	if(start>end) return NULL;
	T->data=xx[start];

	int i;
	for(i=start+1;i<=end;i++){
		if(xx[i]<xx[start]) break;
	}
	for(int j=i;j<=end;j++){
		if(xx[j]>=xx[start]) flag2=0;
	}
	T->left=setMirrorTree(start+1,i-1);
	T->right=setMirrorTree(i,end);
	return T;
}
int main() {
   int n;
   cin>>n;
   for(int i=0;i<n;i++){
   		cin>>xx[i];
   }
   Tree T1=setTree(0,n-1);
   Tree T2=setMirrorTree(0,n-1);
   if(flag1&&T1){
   	cout<<"YES"<<endl;
   		fun(T1);
   	for(int i=0;i<post.size();i++){
   		if(i) cout<<" ";
   		cout<<post[i];
   }
   }
   else if(flag2&&T2){
   	cout<<"YES"<<endl;
   	fun(T2);
   	for(int i=0;i<post.size();i++){
   		if(i) cout<<" ";
   		cout<<post[i];
   }
   }
   else cout<<"NO"<<endl;
   return 0;
}

又发现了一种方法
参考大佬大佬链接

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int xx[N],flag;
vector<int> post;
void JudgeTree(int start,int end){
	if(start>end) return;
	int tl=end;//左子树的右区间,第一个小于
	int tr=start+1;//右子树的左区间,第一个大于等于 	
	int data=xx[start];
	if(flag){
		while(tl>start&&xx[tl]>=data) tl--;
		while(tr<=end&&xx[tr]<data) tr++;
	}
	else{//左子树大于等于,右子树小于 
		while(tl>start&&xx[tl]<data) tl--;
		while(tr<=end&&xx[tr]>=data) tr++;
	}
	if(tr-tl!=1) return;
	JudgeTree(start+1,tl);
	JudgeTree(tr,end);
	post.push_back(data);
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>xx[i];
	flag=1;
	JudgeTree(0,n-1);
	if(post.size()!=n){
		flag=0;
		post.clear();
		JudgeTree(0,n-1);
	}
	if(post.size()==n){
		cout<<"YES"<<endl;
		for(int i=0;i<post.size();i++){
			if(i) cout<<" ";
			cout<<post[i];
		}
	}
	else cout<<"NO"<<endl;
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值