您可以使用“扫描线”技术在 线性时间 (O(n)) 中找到所有 x 和 x 中的 [x - within, x + within] 区间内的整数(请参阅How to Find All Overlapping Intervals 和 Sub O(n^2) algorithm for counting nested intervals?)。
要从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 中的重复值;您可以在Event 中为每个x 添加索引,并使用字典index -> x 而不是started 集合。