任何迭代L1
,L2
每次都迭代,将花费二次时间。改善这一点的唯一方法是避免遍历所有L2
. (有一个类似的问题,从L
最后删除重复。)
如果你使用set
for L2
(和 for L
),当然每in L2
一步都是常数时间,所以整体算法是线性的。而且您始终可以构建自己的哈希表实现,而不是使用set
. 但这是很多工作。
使用二叉搜索树,甚至只是一个排序列表和一个binary_find
函数,您都可以在 O(N log N) 中完成。这binary_find
更容易自己编写。所以:
S2 = sorted(L2)
L = [element for element in L1 if binary_find(element, S2)]
S = remove_adjacent(sorted(L))
或者,更简单地说,也对 L1 进行排序,然后你就不需要了remove_adjacent
:
S1, S2 = sorted(L1), sorted(L2)
L = []
for element in S1:
if binary_find(element, S2) and (not L or L[-1] != element):
L.append(element)
无论哪种方式,这是 O(N log N),其中 N 是较长列表的长度。对比一下,原来是O(N^2),其他答案是O(N^3)。当然它有点复杂,但它仍然很容易理解。
您需要编写binary_find
(并且,如果适用,remove_adjacent
),因为我假设您不想使用 stdlib 之外的东西,如果您甚至不想使用额外的内置函数。但这真的很容易。例如:
def binary_find(element, seq):
low, high = 0, len(seq),
while low != high:
mid = (low + high) // 2
if seq[mid] == element:
return True
elif seq[mid] < element:
low = mid+1
else:
high = mid
return False
def remove_adjacent(seq):
ret = []
last = object()
for element in seq:
if element != last:
ret.append(element)
last = element
return ret
如果你甚至不想使用sorted
or list.sort
,你也可以很容易地编写自己的排序。