由于这来自编程挑战,这里有一个列表长度具有线性复杂度的解决方案(使用组合将获得二次复杂度):
from collections import defaultdict
def count_pairs_summing_to(lst, n):
element_counter = defaultdict(int)
count = 0
for x in lst:
if (n - x) in element_counter:
count += element_counter[n - x]
element_counter[x] += 1
return count
我们的想法是对数据进行一次传递,并跟踪我们之前在哈希表中看到的元素。
当我们看到一个新元素x时,我们只需要知道我们之前是否见过30 - x。
我们还会记录我们看到每个元素的次数,以确保我们计算重复对(例如 count_pairs_summing_to([10, 10, 20, 25], 30) 应该返回 2。)。
一些基准测试:
lst = [10, 13, 15, 18, 20, 15]
%timeit sum(i+j==30 for i,j in combinations(lst,2))
100000 loops, best of 3: 3.35 µs per loop
%timeit len([(ii,jj) for i, ii in enumerate(lst) for j, jj in enumerate(lst[i+1:]) if ii+jj==30])
100000 loops, best of 3: 6.59 µs per loop
%timeit count_pairs_summing_to(lst, 30)
100000 loops, best of 3: 2.92 µs per loop
# With a slightly bigger list.
import numpy.random as random
big_lst = list(random.randint(0, 100, size=1000))
%timeit len([(ii,jj) for i, ii in enumerate(big_lst) for j, jj in enumerate(big_lst[i+1:]) if ii+jj==30])
10 loops, best of 3: 125 ms per loop
%timeit sum(i+j==30 for i,j in combinations(big_lst,2))
1 loops, best of 3: 1.21 s per loop
# The previous one was surprisingly slow but it can be fixed:
%timeit sum(1 for i,j in combinations(big_lst,2) if i+j==30)
1 loops, best of 3: 88.2 ms per loop
%timeit count_pairs_summing_to(big_lst, 30)
1000 loops, best of 3: 504 µs per loop