您可以使用“扫描线”技术在线list2
性[x - within, x + within]
时间x
(list1
O(n)
要从list1
您需要的O(m)
时间枚举相应的时间间隔,其中m
是时间间隔的数量,即,整体算法是O(n*m)
:
from collections import namedtuple
from heapq import merge
def find_items_within(list1, list2, within):
issorted = lambda L: all(x <= y for x, y in zip(L, L[1:]))
assert issorted(list1) and issorted(list2) and within >= 0
# get sorted endpoints - O(n) (due to list1, list2 are sorted)
Event = namedtuple('Event', "endpoint x type")
def get_events(lst, delta, type):
return (Event(x + delta, x, type) for x in lst)
START, POINT, END = 0, 1, 2
events = merge(get_events(list1, delta=-within, type=START),
get_events(list1, delta=within, type=END),
get_events(list2, delta=0, type=POINT))
# O(n * m), m - number of points in `list1` that are
# within distance from given point in `list2`
started = set() # started intervals
for e in events: # O(n)
if e.type is START: # started interval
started.add(e.x) # O(m) is worst case (O(1) amortized)
elif e.type is END: # ended interval
started.remove(e.x) # O(m) is worst case (O(1) amortized)
else: # found point
assert e.type is POINT
for x in started: # O(m)
yield x, e.x
允许重复值list1
;x
您可以为每个输入添加索引Event
并使用字典index -> x
而不是started
集合。