HDU5701(技巧暴力)

一开始看这道题目的时候让我想起来以前看过的一道面试题,结果写上去超时。。

接下来入正题,那道面试题我在最后分享一下。

数据只有8000,n^2能过,只能暴力枚举每个数了。

首先把大于arr[i]的数改成1小于改成-1,等于改成0(其实只有自己等于自己)

一般连续区间的题目大概率都用到线段树和前缀和,这里用到了前缀和。

从i开始到n把前缀和都记录下来,这样如果前缀和为0就表示该数为中位数。(右扫描)

接下来在计算i到1的(左扫描),计算过程中如果左边的前缀于右边的前缀和相加为0,

那么要ans++,但这样比较费时,那么用Hash数组记录下右边前缀和,下标表示前缀和,值表示该等于前缀和的前缀有多少个,

这样ans+=Hash[],就大大节约了时间,但是前缀和可能为负数,所以加一个偏移量med=8000;

代码如下:

                #include<iostream>
                #include<cstring>
		using namespace std;
		
		int arr[8005];//数组 
		int sym[8005];//0 -1 1 的标志 
		int sum[8005];//前缀和 
		int Hash[8005*2];//以前缀和为下标记录等于前缀和的前缀个数 
		const int med=8000;									
		
		int main()
{
	        int n;
		while(cin>>n)
		{
			for(int i=1;i<=n;i++)
			{
				scanf("%d",&arr[i]); 
			}
			
			for(int i=1;i<=n;i++)
			{
				memset(Hash,0,sizeof(Hash));
				for(int j=1;j<=n;j++)
				{
					if(arr[i]>arr[j])
						sym[j]=-1;
					else if(arr[i]<arr[j])
					    sym[j]=1;
					else sym[j]=0;
				}
				
				sum[i]=0;
				Hash[med+sum[i]]++;
				
				for(int j=i+1;j<=n;j++)//右扫描 
				{
					sum[j]=sum[j-1]+sym[j];
					Hash[med+sum[j]]++;
				}
				
				int ans=0;
				ans+=Hash[med+0];    
				for(int j=i-1;j>=1;j--)//左扫描更新答案 
				{
					sum[j]=sum[j+1]+sym[j];
					ans+=Hash[med-sum[j]];
				}
				
				if(i!=n) printf("%d ",ans);
				else 	 printf("%d\n",ans);
			}		
		}	    
} 

分享一下我见的那道面试题:

给你一个随时增加元素的数组,要求更新他的中位数。

当第一个元素来的时候中位数即为该数,

这个时候维护一个大顶堆和一个下顶堆

大顶堆放入比中位数小的元素,小顶堆放入比中位数大的元素。

当左右堆的大小差值超过1时,便调整左右堆,中位数加入元素更少的一个堆

然后中位数等于另一个堆的堆顶元素,这样便实现了动态调整。

维护的时间复杂度是 lon n。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值