PAT A1143

给出一个二叉排序树的前序序列,再任意给两个点,求两个点的最小祖先

一开始:
按照套路,先建树,然后遍历树的思想。
建树采用输入一个点然后插入树的方法。
遍历树用了map数组。
此时有三个点运行超时,cin、cout改为scanf和printf都未能解决问题。

于是开始从库函数下手。
后来发现,map数组改为使用int数组,运行变快了

原来用的遍历方法是用两个vector数组保存树根到两个点的路径,然后逐个比较得到两条路径最后一个相等的点。

后来:
采用了新的代码,从叶子开始后序递归,遍可以得到最低公共祖先的结点,这个算法真的开了我的眼,以至于我到现在还没看通透。。。

Node* findnode(Node* r,int a,int b)
{
    if(r==NULL)
        return NULL;
    if(a==r->key||b==r->key)
        return r;
	Node* left=findnode(r->left,a,b);
	Node* right=findnode(r->right,a,b);
    if(left!=NULL&&right!=NULL)
        return r;
    return left==NULL?right:left;
}

同时,给出一个二叉排序树的前序序列,其从小到大重新排序后,即为中序序列。查了别人的代码后,用了先一次性输入存储前序和中序序列,然后再一次性建树的方法,运行超时解决。

再后来:
发现一个神仙的代码,根本就没有建树,运行时间大幅减少。

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=10010;
 
int pre[maxn];
int k,n;
 
int main(){
	scanf("%d%d",&k,&n);
	for(int i=0;i<n;i++){
		scanf("%d",&pre[i]);
	}
	int u,v;
	for(int q=0;q<k;q++){
		bool findU=false,findV=false;
		scanf("%d%d",&u,&v);
		int posU,posV;
		for(int i=0;i<n;i++){
			if(pre[i]==u){
				findU=true;
				posU=i;
			}
			if(pre[i]==v){
				findV=true;
				posV=i;
			}
		}
		if(findU==false&&findV==false){
			printf("ERROR: %d and %d are not found.\n",u,v);
			continue;
		}
		if(findU==false){
			printf("ERROR: %d is not found.\n",u);
			continue;
		}
		if(findV==false){
			printf("ERROR: %d is not found.\n",v);
			continue;
		}
		
		bool isSwap=false;//标记u,v是否交换过 
		if(u>v){
			swap(u,v);
			swap(posU,posV);
			isSwap=true;
		}
		int num=-1;
		for(int i=0;i<n;i++){
			if(pre[i]>u&&pre[i]<=v&&i<posV){//i欲成为v的祖先,在pre序列中,i必须在v之前 
				num=i;
				break;
			}
		}
		if(num!=-1){
			if(isSwap){//u,v交换过 
				swap(u,v);
			}
			printf("LCA of %d and %d is %d.\n",u,v,pre[num]);
		}
		else{
			if(posU>posV){
				swap(u,v);
			}
			printf("%d is an ancestor of %d.\n",u,v);
		} 
	}
	return 0;
}

--------------------- 
作者:harvien9 
来源:优快云 
原文:https://blog.youkuaiyun.com/qq_38705851/article/details/82387888 
版权声明:本文为博主原创文章,转载请附上博文链接!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值