我不是算法专家,所以请原谅这个问题。
我有一个包含元素100K元素的列表A。我还有另一个包含100K元素的列表B。假设a是列表A中的元素,b是列表B中的元素。我想找出总和小于100的(a,b)组合。
一种明显的方法是:
results = []
for a in A:
for b in B:
if (a+b) < 100:
results.append((a,b))
但是这种方法的时间复杂度为O(n * m)= 100K * 100K,这非常大。是否有任何快速算法可以在内存和时间方面更有效地计算所需的输出。如果是,可以在python中实现吗?
答案 0 :(得分:9)
对两个列表进行排序(O(n log n)
和O(m log m)
,如果值受约束,则可能更少)。
然后,您可以简单地为a
中的每个A
找到b
中最大的B
,使得(a+b) < 100
。每个较小的b
也会满足该条件。
可以使用二进制搜索在b
中找到下限来找到某些a
中最大的B
。然后,从最大的a
开始下降,您可以保留与上一个b
对应的a
的列表,因为总和将变小。
答案 1 :(得分:1)
不,在最坏的情况下,您无法得到比这更好的。考虑一个病理情况,其中A和B的每个组合都必须附加到列表中:
A = list(range(0, -n, -1))
B = list(range(0, -m, -1))
因为每对必须附加,所以您正在执行O(m * n)
操作。
如果您只需要计算组合的数量,那么情况可能会不同。
答案 2 :(得分:0)
您的标准是可以定义为范围的a + b < 100
。在这种情况下,我将其定义为wanted_result_range = range(0, 100)
,因为您的列表A和B仅包含正数,因此结果将仅为正值。
运行以下脚本,您将看到我的方法比您提到的“正面”方法快多少。如果定义了更广泛的wanted_result_range,我的解决方案将很糟糕。
import timeit
# http://docs.python.org/3.3/library/timeit.html
print "\nTiming execution times\n"
version1="""
results1 = []
list_A = range(1000)
list_B = range(1000)
wanted_result_range = range(0, 100)
d1 = {}
l3 = []
for key in list_A:
d1[key] = True # Value associated to key is not important and can be any value
for wanted_result in wanted_result_range:
for key2 in list_B:
if ((wanted_result-key2) in d1):
results1.append((key2,wanted_result-key2))
"""
print("Version 1 - Hash table (dictionary) approach")
print(timeit.repeat(version1, number=10, repeat=4))
print('END Version 1\n')
version2="""
results2 = []
list_A = range(1000)
list_B = range(1000)
for a in list_A:
for b in list_B:
if (a+b) < 100:
results2.append((a,b))
"""
print("Version 2 - Frontal approach")
print(timeit.repeat(version2, number=10, repeat=4))
print('END Version 2\n')