如何解决找出间隔中数字的频率
在非重叠间隔中查找元素频率/计数的最有效方法是什么?例如:
limits = [0,25,40,60]
data = [15,5,2,56,45,23,6,59,33,18]
对于上面的列表,我想找到数据中两个相邻限制内的元素数。因此,对于上述内容,计数将类似于:
0-25:6; 25-40:1; 40-60: 3;
我能想到的只有 O(n^2) 时间。有没有更好的方法?
解决方法
不需要 Counter 来计数,因为 bin 的数量是已知的,将 dict 交换到数组访问以进行 binning..
from bisect import bisect_right
def bin_it(limits,data):
"Bin data according to (ascending) limits."
bins = [0] * (len(limits) + 1) # adds under/over range bins too
for d in data:
bins[bisect_right(limits,d)] += 1
return bins
if __name__ == "__main__":
limits = [0,25,40,60]
data = [15,5,2,56,45,23,6,59,33,18]
bins = bin_it(limits,data)
print(f" < {limits[0]:2} :",bins[0])
for lo,hi,count in zip(limits,limits[1:],bins[1:]):
print(f">= {lo:2} .. < {hi:2} :",count)
print(f">= {limits[-1]:2} ... :",bins[-1])
"""
SAMPLE OUTPUT:
< 0 : 0
>= 0 .. < 25 : 6
>= 25 .. < 40 : 1
>= 40 .. < 60 : 3
>= 60 ... : 0
"""
,
我向您推荐这种方法,它按照 O(nlogn)
的顺序实现您想要的limits = [0,60] # m
data = [15,18] # n
data += limits # O(n+m)
data.sort() # O((n+m)log(n+m)) = O(nlogn)
result=dict() # O(1)
cnt = 0 # O(1)
aux ='' # O(1)
i = 0 # O(1)
for el in data: # O(n+m)
if el == limits[i]:
i+=1
if cnt > 0:
aux+='-'+str(el)
result[aux] = cnt # average = O(1)
cnt = 0
aux = str(el)
else:
aux = str(el)
else:
cnt+=1
print(result)
# {'0-25': 6,'25-40': 1,'40-60': 3}
我展示了每个重要行的时间复杂度来计算代码的总时间复杂度。代码的总时间复杂度等于 O((n+m)log(n+m))
,可以表示为 O(nlogn)
。
改进
如果您对输入有一些假设,则可以改进它。如果您有关于 limits
和 data
范围的信息,那么您可以将排序算法更改为 counting sort。计数排序的时间复杂度为O(n)
,代码的总时间复杂度为O(n)
这是一个简单的 O(NlogN)
方法。对数据进行排序,然后使用双指针方法将每个元素放置在正确的间隔中。
limits = [0,60]
data = [15,18]
data.sort()
n,m = len(data),len(limits)
count = [0]*(m-1)
# count[i] represents count between limits[i] and limits[i+1]
low = 0 # lower index of interval we are currently checking
ptr = 0
while ptr < n:
i = data[ptr]
if i >= limits[low] and i <= limits[low+1]:
count[low] += 1
ptr += 1
elif i>=limits[low]:
if low == len(limits)-1:
break
low += 1
print(count)
,
limits = [0,60,80]
data = [15,18,85]
dict_data = {}
i = 0
count = 1
while i < len(limits)-1:
for j in data:
if j in range(limits[i],limits[i+1]):
if '{}-{}'.format(limits[i],limits[i+1]) in dict_data:
dict_data['{}-{}'.format(limits[i],limits[i+1])] +=count
else:
dict_data['{}-{}'.format(limits[i],limits[i+1])] = count
i+=1
print(dict_data)
,
您可以使用计数器(来自集合)来管理计数和平分以进行分类:
from collections import Counter
from bisect import bisect_left
limits = [0,80]
data = [15,18]
r = Counter(limits[bisect_left(limits,d)-1] for d in data)
print(r)
Counter({0: 6,40: 3,25: 1})
这具有 O(NLogM) 的时间复杂度,其中 M 是限制中断的数量,N 是数据项的数量
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。