题目描述
给定 n 个实数,求这n个实数在数轴上相邻2个数之间的最大差值,设计解最大间隙问题的线性时间算法(时间复杂度为O(n))。
输入
第二行n个实数,数据保证这些实数只有一位小数。
输出
样例输入
5
2.3 3.1 7.5 1.5 6.3
样例输出
3.2
【参考博客】https://blog.csdn.net/llwwlql/article/details/52434280
【题解】
百思不得其解,为什么会用到鸽笼原理,后来老师讲解后,发现还真的是鸽笼原理。
核心思想是:
n个点,其中两个点作为左右边界。剩下n-2个点,在n-1个格子必定有一个为空。
比如:1,2,3,4。
那么利用1,4作为左右边界,然后剩下两个数字,我们把[1,4]这个区间等分划分成n-1个区间。
那么就会出现 [ 1 , 2 ] [ 2 , 3 ] [ 3 , 4 ] 这三个区间,剩下两个数字进行投球测试,必定有一个区间是空的。
最大的间隙必定会在这个空隙与左右区间的点结合后组成最大的间隙。
1、扫描 找出所有点的最大值和最小值。
2、划分区间 区间的长度为: len = ( Max - Min ) / ( n - 2 ) .
3、处理每一个区间
a、求出每一个点对应在哪个区间,( a[i] - Min ) / ( len )
b、把每一个点都安放好对应的区间(Block)里面
c、顺便统计 区间里的个数,区间里的左右边界:即 在区间里的最大值和最小值。
4、然后过程中跑就行了,只需要在跑的过程中找出左边区间的最大值,和当前区间最小值进行更新答案,同时更新最后一个右端点。
5、特判两种情况:
a、如果第3步骤出现 长度等于0 时,区间编号求解时:len作为分母,出现这种情况其实答案直接输出0即可。
b、如果出现只有两个数的情况下,如果下标是从0开始更新的,如果处理不好就会在在第一个区间内不更新值。
【代码1】
1 #include <stdio.h> 2 #define N 2e7+10 3 #define mmax 1e5 4 #define mmin 0 5 6 int n,count[N]={0}; 7 double num[N], maxNum[N],minNum[N]; 8 9 10 int main() 11 { 12 int i,bucket; 13 double maxValue=mmin, minValue=mmax,delta,begin,maxgap=0.,temp; 14 15 scanf("%d",&n); 16 17 //the first step, input and compute the max and min value. 18 for(i=0;i<n;i++){ 19 scanf("%lf",&num[i]); 20 maxNum[i]=mmin; 21 minNum[i]=mmax; 22 23 if(num[i]>maxValue) 24 maxValue=num[i]; 25 26 if(num[i]<minValue) 27 minValue=num[i]; 28 } 29 30 //the second step, partion the numbers into buckets 31 delta=(maxValue-minValue)/(n-1); 32 33 34 if( delta == 0 ) { 35 printf("0.0 "); 36 return 0 ; 37 } 38 39 for(i=0;i<n;i++){ 40 bucket=(int)((num[i]-minValue)/delta); 41 count[bucket]++; 42 if(maxNum[bucket]<num[i]) 43 maxNum[bucket]=num[i]; 44 if(minNum[bucket]>num[i]) 45 minNum[bucket]=num[i]; 46 } 47 48 49 /* 50 //deal with the last bucket, containing the max Number 51 if(count[n-2]==0) 52 minNum[n-2]=maxNum[n-2]=maxValue; 53 else 54 maxNum[n-2]=maxValue; 55 56 count[n-2]++; 57 */ 58 59 60 //the third step, retrieve the max gap 61 begin=maxNum[0]; 62 63 //把 i < n - 1 改成 i < n 64 for(i=1;i<n;i++){ 65 if(count[i]){ 66 temp=minNum[i]-begin; 67 if(temp>maxgap) 68 maxgap=temp; 69 begin=maxNum[i]; 70 } 71 } 72 73 printf("%.1f ",maxgap); 74 75 return 0; 76 }
【代码2】
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 2e7 + 10 ; 5 const double inf = 1e18 ; 6 double Block[N][2] , a[N] ; 7 double Max ; 8 double Min ; 9 double Len ; 10 int n,Cnt[N] ; 11 12 int main(){ 13 14 /*输入,同时更新最大最小值*/ 15 scanf("%d",&n); 16 17 18 scanf("%lf",&a[1]); 19 Max = a[1] ; 20 Min = a[1] ; 21 Block[1][0] = inf ; 22 Block[1][1] = -inf ; 23 24 for( int i=2 ; i <= n ; i++ ){ 25 scanf("%lf",&a[i]); 26 Max = max( Max , a[i] ); 27 Min = min( Min , a[i] ); 28 Block[i][0] = inf ; 29 Block[i][1] = -inf ; 30 } 31 32 /* 处理每一个间隙 */ 33 /* n 个点 n - 1 个区间 */ 34 Len = ( Max - Min ) / ( n - 1 ) ; 35 36 if( n == 2 ){ 37 printf("%.1f ",Max-Min); 38 return 0; 39 } 40 /* 扫描每一个点,把点放置在对应的Block里面 */ 41 for( int i = 1 ; i <= n ; i++ ){ 42 int idx = int( ( a[i] - Min ) / Len ) + 1 ; 43 Cnt[idx] ++ ; 44 Block[idx][0] = min( Block[idx][0] , a[i] ); 45 Block[idx][1] = max( Block[idx][1] , a[i] ); 46 } 47 48 double Ans = 0 , Last = Min ; 49 for( int i = 1 ; i <= n-1 ; i++ ){ 50 if( Cnt[i] ){ 51 if( Ans < Block[i][0] - Last ){ 52 Ans = Block[i][0] - Last ; 53 } 54 Last = Block[i][1]; 55 } 56 } 57 58 //特判最后一个点的位置 59 60 if( Ans < Max - Last ){ 61 Ans = Max - Last ; 62 } 63 64 printf("%.1f ",Ans); 65 return 0; 66 }
【代码3】
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Sheryang main 4 const int maxn=2e7+7; 5 typedef long long ll; 6 const int mod=1e9+7; 7 #define HEAP(...) priority_queue<__VA_ARGS__ > 8 #define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > > 9 template<class T> inline void gmin(T &x,const T &y){x=x>y?y:x;} 10 template<class T> inline void gmax(T &x,const T &y){x=x<y?y:x;} 11 template<class T> inline bool Gmin(T &x,const T &y){return x>y?x=y,1:0;} 12 template<class T> inline bool Gmax(T &x,const T &y){return x<y?x=y,1:0;} 13 const int BufferSize=1<<16; 14 char buffer[BufferSize],*Bufferhead,*Buffertail; 15 bool Terminal; 16 inline char Getchar(){ 17 if(Bufferhead==Buffertail){ 18 int l=fread(buffer,1,BufferSize,stdin); 19 if(!l){Terminal=1;return 0;} 20 Buffertail=(Bufferhead=buffer)+l; 21 } 22 return *Bufferhead++; 23 } 24 template<class T>inline bool read(T &x){ 25 x=0;char c=Getchar(),rev=0; 26 while(c<'0'||c>'9'){rev|=c=='-';c=Getchar();if(Terminal)return 0;} 27 while(c>='0'&&c<='9') x=x*10+c-'0',c=Getchar(); 28 if(c=='.'){ 29 c=Getchar();double t=0.1; 30 while(c>='0'&&c<='9') x=x+(c-'0')*t,c=Getchar(),t=t/10; 31 } 32 x=rev?-x:x; 33 return 1; 34 } 35 template<class T1,class T2> inline bool read(T1 &x,T2 &y){return read(x)&read(y);} 36 template<class T1,class T2,class T3> inline bool read(T1 &x,T2 &y,T3 &z){return read(x)&read(y)&read(z);} 37 template<class T1,class T2,class T3,class T4> inline bool read(T1 &x,T2 &y,T3 &z,T4 &w){return read(x)&read(y)&read(z)&read(w);} 38 inline bool reads(char *x){ 39 char c=Getchar(); 40 while(c<33||c>126){c=Getchar();if(Terminal)return 0;} 41 while(c>=33&&c<=126) (*x++)=c,c=Getchar(); 42 *x=0;return 1; 43 } 44 /** keep hungry and keep calm! **/ 45 46 47 double a[maxn],Cage[maxn][2]; 48 int cot[maxn]; 49 int Sheryang(){ 50 51 //freopen("input.txt","r",stdin); 52 //freopen("out1.txt","w",stdout); 53 54 int n;read(n); 55 for(int i=1;i<=n;i++){ 56 read(a[i]); 57 } 58 59 double Max = a[1],Min = a[1]; 60 for(int i=2;i<=n;i++){ 61 gmax(Max,a[i]); 62 gmin(Min,a[i]); 63 } 64 double gap = (Max - Min) / (n-1); 65 66 if(gap == 0){ 67 printf("0.0 "); 68 return 0; 69 } 70 71 for(int i=1;i<=n;i++){ 72 Cage[i][0] = 1e18; 73 Cage[i][1] = -1e18; 74 } 75 76 for(int i=1;i<=n;i++){ 77 int pos = (int)((a[i] - Min)/gap) + 1; 78 cot[pos] ++; 79 gmin(Cage[pos][0],a[i]); 80 gmax(Cage[pos][1],a[i]); 81 } 82 83 double last = Min, ans = 0; 84 for(int i=1;i<=n;i++){ 85 if(cot[i]){ 86 double tmp = Cage[i][0] - last; 87 if(tmp > ans){ 88 ans = tmp; 89 } 90 last = Cage[i][1]; 91 } 92 } 93 if(Max - last > ans){ 94 ans = Max - last; 95 } 96 97 printf("%.1f ",ans); 98 return 0; 99 }