假设有两个已排序的列表A和B。
A和B中的条目数可能会有所变化。(它们可以非常小/巨大。它们可以相似/显着不同)。
这种功能已知的最快算法是什么?
有没有人能给我一个想法或参考文献?
假设有两个已排序的列表A和B。
A和B中的条目数可能会有所变化。(它们可以非常小/巨大。它们可以相似/显着不同)。
这种功能已知的最快算法是什么?
有没有人能给我一个想法或参考文献?
A
有 m
个元素,B
有 n
个元素,并且 m ≥ n
。 从信息论的角度来看,我们能做到最好的是: (m + n)!
lg -------- = n lg (m/n) + O(n)
m! n!
由于要验证空交集,我们基本上必须执行排序合并,因此需要进行比较。通过遍历 B
并在 A
中保持“游标”以指示应插入的最近一个元素的位置来维护排序顺序。我们使用指数搜索来推进光标,总成本大致为:
lg x_1 + lg x_2 + ... + lg x_n,
其中x_1 + x_2 + ... + x_n = m + n
是m
的某个整数划分。由于lg
的凹性,这个和是O(n lg (m/n))
。
我不确定这是否是最快的选项,但以下是一种时间复杂度为O(n+m)
的方法,其中n
和m
是您列表的大小:
这里是一个简单且经过测试的Python实现,它使用二分搜索来推进两个列表的指针。
它假设输入的两个列表都已排序且不包含重复项。
import bisect
def compute_intersection_list(l1, l2):
# A is the smaller list
A, B = (l1, l2) if len(l1) < len(l2) else (l2, l1)
i = 0
j = 0
intersection_list = []
while i < len(A) and j < len(B):
if A[i] == B[j]:
intersection_list.append(A[i])
i += 1
j += 1
elif A[i] < B[j]:
i = bisect.bisect_left(A, B[j], lo=i+1)
else:
j = bisect.bisect_left(B, A[i], lo=j+1)
return intersection_list
# test on many random cases
import random
MM = 100 # max value
for _ in range(10000):
M1 = random.randint(0, MM) # random max value
N1 = random.randint(0, M1) # random number of values
M2 = random.randint(0, MM) # random max value
N2 = random.randint(0, M2) # random number of values
a = sorted(random.sample(range(M1), N1)) # sampling without replacement to have no duplicates
b = sorted(random.sample(range(M2), N2))
assert compute_intersection_list(a, b) == sorted(set(a).intersection(b))