杨继增+SA19010046+第一次作业(编程)
二、算法实现题
- 最大间隙问题
(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 n∗logn)显然不符合题意,然后我查询了一下线性的排序方式,发现基数排序可以做到这一点。但是对于最大间隙问题来说,其实可以并不需要完全一个排序,参考桶排序的思想,可以将这个这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=(max−min)/(n−1),其中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
n−2个数,对于数
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=⌊lenai−min⌋+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
n−1个桶,而数据还有
n
−
2
n-2
n−2,每个桶都是等间隔的,根据鸽巢原理,至少有一个桶为空,所以,最大间隔距离必然存在于桶与桶之间,而非桶内,所以对于落在同一个桶内的数据不需要进行排序,只需要更新桶内的
m
a
x
,
m
i
n
max,min
max,min参数。然后利用桶的
m
a
x
.
m
i
n
max.min
max.min参数进行间隙最大值的计算。
程序的输入输出:
input | ouput |
---|---|
5 | 3.2 |
2.3 3.1 7.5 1.5 6.3 | |
7 | 3.5 |
2.3 3.1 7.5 1.5 6.3 6.3 11 | |
13 | 10 |
1 2 2 4 5 7 7 30 10 11 11 20 30 | |
7 | 992.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)