文/一觉亮天
鸽巢原理经常用在判定存在性的问题。
鸽巢原理: n+1只鸽子往n个巢子里飞,则可以确定至少有一个巢里有大于等于二只鸽子。 m只鸽子往n个巢里飞, 则可以确定至少有一个巢里有大于等于ceiling(m/n)只鸽子。
下面举一个利用鸽巢原理解题的例子。
数轴上的一组无序实数,求出相邻两点间的最大间隙。要求算法的时间复杂度为n。
解此题最容易想到的就是先把这组实数排序,然后用一个循环遍历一遍排序后的序列,就可以找到相邻两点间的最大间隙。 但是我们知道,最快的排序算法的平均时间复杂度都是n*log(n), 如快速排序和归并排序。 而如插入排序和冒泡排序等的时间复杂度为n的平方。所以这种办法是行不通的。
关于此题,我是一直没能想出时间复杂度为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 } }