Algrithm Analysis之最大间隙

杨继增+SA19010046+第一次作业(编程)

二、算法实现题

  1. 最大间隙问题
    (1) 问题描述:最大间隙问题是指,给定 n 个实数 x1,x2 ,…, x n ,求这 n 个数在实轴上相邻 2 个数之间的最大差值。假设对任何实数的下取整函数耗时 O( 1 ) ,设计最大间隙问题的线性时间算法。
    (2) 算法设计:对于给定的 n 个实数 x 1 , x2 ,…, x n ,计算它们的最大间隙。
    (3) 数据输入:输入数据由文件名 input.txt 的文本文件提供。文件的第 1 行有 1
    个正整数 n 。接下来 1 行中有 n 个实数 x 1 , x 2 ,…, xn 。
    (4) 结果输出:将找到的最大间隙输出到文件 output.txt。

解答:
使用的数据结构:
python语言,借助列表数据结构即可,列表中每个元素由四个数据表示,分别为桶的编号,桶中的最小值,桶中的最大值,标志位。
eg:

In [1]: c                                                                      
Out[1]: [[0, 0, 0,1], [1, 1, 1,1], [2, 4, 8,1], [3, 9, 27,1], [4, 16, 64,1]]
In [2]: for x in c: 
    ...:     print(x)                                                                      
[0, 0, 0,1]
[1, 1, 1,1]
[2, 4, 8,1]
[3, 9, 27,1]
[4, 16, 64,1]

如上图所示,c代表所有桶的集合,c中的每一个元素
[桶号,桶内最小值,桶内最大值,标志flag] ;
例如第一个元素为[0,0,0,1]即桶的编号为0,桶中最小值为0,最大值为0,最后一个1为flag表示此桶已经更新。以此类推。[4,16,64]即桶的编号为4,桶中最小值为16,最大值为64,flag为1表示以及更新。

问题分析:最大间隔问题如果按照先排序后寻找最大值的方式。排序算法比较排序的话,最小的复杂度为O( n ∗ log ⁡ n n*\log n nlogn)显然不符合题意,然后我查询了一下线性的排序方式,发现基数排序可以做到这一点。但是对于最大间隙问题来说,其实可以并不需要完全一个排序,参考桶排序的思想,可以将这个这n个数进行一个分段,比如分成n+1段,然后利用鸽巢原理,至少有一个为空,如果我们时等间隔划分,则最大间隙肯定是存在与桶(每个间隔相当于一个桶)外部而非内部。这样就不需要对于桶内部的数据进行排序。

算法设计
1、首先找到这组数的 m a x max max m i n min min,将这两个分为一个单独的组
2、然后计算 l e n = ( m a x − m i n ) / ( n − 1 ) len=(max-min)/(n-1) len=(maxmin)/(n1),其中len为每一段间隔的大小。
3、初始化桶;每个都初始化为 [ i , m a x , m i n , 0 ] , [i,max,min,0], [i,max,min,0]
4、更新桶内的值;更新桶0的表示则为[0, m i n min min, m i n min min,1],桶n,更新为 [ n , m a x , m a x , 0 ] [n,max,max,0] [n,max,max,0];遍历剩下的 n − 2 n-2 n2个数,对于数 a i a_{i} ai, t m p = ⌊ a i − m i n l e n ⌋ + 1 tmp= \lfloor \dfrac{a_{i}-min}{len} \rfloor+1 tmp=lenaimin+1,tmp即需要更新的桶的编号。更新规则,

if( ai<bunket[tmp][1]):
 	bunket[tmp][1]=ai
 	bunket[tmp][3]=1
if(ai>bunket[tmp][2]):
 	bunket[tmp][2]=ai
 	bunket[tmp][3]=1

注意
这里第二个不可以使用 elif,此与在bunket(桶)初始化的有关桶的每一个元素初始化为[i,max_d,min_d,0]
5、以此遍历,对于flag=0的

	bunket[tmp][2]=bunket[tmp][1]=bunket[tmp-1][2]

6、查找最大间隙,桶外的距离。

复杂度分析:查找 m a x , m i n max,min max,min复杂度为 O ( n ) O(n) O(n),更新桶内参数,只需遍历一遍数据,复杂度为 O ( n ) O(n) O(n),最后查找最大间隔为 O ( n ) O(n) O(n);故总体的复杂度为 O ( n ) O(n) O(n),即线性复杂度

正确性证明
首先对于 n n n个数据,我们将最小值与最大值放在第0个桶与第 n n n个桶,剩下 n − 1 n-1 n1个桶,而数据还有 n − 2 n-2 n2,每个桶都是等间隔的,根据鸽巢原理,至少有一个桶为空,所以,最大间隔距离必然存在于桶与桶之间,而非桶内,所以对于落在同一个桶内的数据不需要进行排序,只需要更新桶内的 m a x , m i n max,min max,min参数。然后利用桶的 m a x . m i n max.min max.min参数进行间隙最大值的计算。
程序的输入输出

inputouput
53.2
2.3 3.1 7.5 1.5 6.3
73.5
2.3 3.1 7.5 1.5 6.3 6.3 11
1310
1 2 2 4 5 7 7 30 10 11 11 20 30
7992.5
2.3 3.1 7.5 1.5 6.3 6.3 1000

代码附录

'''
@article{Maximum gap proble
  author={Jizeng Yang},
  title={Linear Algorithm for Maximum Gap Problem},
  date={2020.3.16},
}
'''
'''
python 3.6
'''
from __future__ import print_function
import string

def Max_min(data):
    #find max and min:m=[min,max]
    m=[data[0],data[0]]
    for num in data:
        if(m[0]>num):
            m[0]=num
        elif(m[1]<num):
            m[1]=num
    return m
def Read_data():
     with open("input.txt", "r") as fin:
        text = fin.read()
        fin.close()
        data=[string.atof(w) for w in text.split()]
        return data
def Write_result(result):
    fout=open("output.txt","w")
    fout.write(str(result))
    fout.close


def main():
    data=Read_data()
    #print(data)
    N=int(data.pop(0))
    #print(N)
    print(data)
    M=Max_min(data)
    max_d=M[1]
    min_d=M[0]
    #print(M)
    #initialise bucket number:N+2

    bunket=[[i,max_d,min_d,0] for i in range(0,N+1)]
    #print(bunket)
    len_d=(max_d-min_d)/(N-1)
    #print(len_d)

    bunket[0]=[0,min_d,min_d,1]
    bunket[N]=[N,max_d,max_d,1]
    #Traversing the data list
    for ai in data:
        tmp=int((ai-min_d)//len_d)+1#
        if(ai<bunket[tmp][1]):
            bunket[tmp][1]=ai
            bunket[tmp][3]=1
        if(ai>bunket[tmp][2]):
            bunket[tmp][2]=ai
            bunket[tmp][3]=1
    #operation of flag==0
    #print(bunket)
    result=0
    for para in bunket:
        if(para[3]==0):
            para[2]=para[1]=bunket[para[0]-1][2]
        if(para[0]):
            difference=para[1]-bunket[para[0]-1][2]
            if(result<difference):
                result=difference
    #print("****\n",bunket)
    print(result)
    Write_result(result)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值