鸽巢原理及应用

/一觉亮天

鸽巢原理经常用在判定存在性的问题。

 

鸽巢原理: n+1只鸽子往n个巢子里飞,则可以确定至少有一个巢里有大于等于二只鸽子。 m只鸽子往n个巢里飞, 则可以确定至少有一个巢里有大于等于ceiling(m/n)只鸽子。

 

下面举一个利用鸽巢原理解题的例子。

 

数轴上的一组无序实数,求出相邻两点间的最大间隙。要求算法的时间复杂度为n

 

解此题最容易想到的就是先把这组实数排序,然后用一个循环遍历一遍排序后的序列,就可以找到相邻两点间的最大间隙。 但是我们知道,最快的排序算法的平均时间复杂度都是n*log(n) 如快速排序和归并排序。 而如插入排序和冒泡排序等的时间复杂度为n的平方。所以这种办法是行不通的。

 

关于此题,我是一直没能想出时间复杂度为n的算法。 直到在书中找到了答案。算法的思路如下。

 

  1. 找出这组数的最大值和最小值。 (时间复杂度为n
  2. 在最大值和最小值之间等间隔地构造n-1个桶,把除了最大值和最小值的n-2个数按照他们各自的值安排在相应的桶里。 每支桶里只需要记录属于这个桶的最大数和最小数。 (时间复杂度为n
  3. 根据鸽巢原理,有n-2个数,n-1个桶,则至少有一个桶是空的。 所以最大间隙只能存在于桶间和桶与最大值和最小值之间,不会出现在桶内。在最小值、各个桶和最大值之间遍历一遍,就可以求出最大间隙。 (时间复杂度为n

 

下面是程序代码。

 

 

import scala._ object Pigeon { def main(args:Array[String]){ //read maximum number of real numbers. val num=readInt() //read num double number val points=new Array[Double](num) for (i<-0 until num){ points(i)=readDouble() } //get the index of minimum & maximum val minIdx=min(points) val maxIdx=max(points) //initialize (num-1) bucket, maximum in 1 while minimum in 2 stands for empty bucket val bucket=new Array[(Double,Double)](num-1) for(i<-0 until num-1){ bucket(i)=(points(maxIdx),points(minIdx)) } //fill double numbers in bucket for(i<-0 until num){ //not include maximum and minimum if(i!=minIdx && i!=maxIdx){ var bucket_index = ((points(i)-points(minIdx))*(num-1) /(points(maxIdx)-points(minIdx))).toInt var minBucketVal=bucket(bucket_index)._1; var maxBucketVal=bucket(bucket_index)._2; if ( minBucketVal > points(i) ){ minBucketVal = points(i) } if (maxBucketVal < points(i) ) { maxBucketVal = points (i) } bucket(bucket_index)=(minBucketVal,maxBucketVal) } } //iterate to get max_interval var max_interval:Double=0.0d; var previous_val:Double=points(minIdx) for(i<-0 until (num-1) ) { var (minBucketVal,maxBucketVal) = bucket(i) //it is not empty bucket if(minBucketVal<=maxBucketVal){ var cur_interval=minBucketVal - previous_val if(cur_interval>max_interval) max_interval=cur_interval previous_val=maxBucketVal } } var cur_interval=points(maxIdx)-previous_val if(cur_interval>max_interval) max_interval=cur_interval //output the result println(max_interval.toString) } def min(ary:Array[Double]):Int={ var idx:Int= 0; var i:Int=0; for(i<-0 until ary.length){ if ( ary(i) < ary(idx) ){ idx=i } } idx } def max(ary:Array[Double]):Int={ var idx:Int= 0; var i:Int=0; for(i<-0 until ary.length){ if ( ary(i) > ary(idx) ){ idx=i } } idx } }

你可能感兴趣的:(算法,object,import,include,Numbers)