返回列表中任何两个项的元组,如果求和则给定int

时间:2014-05-30 22:53:28

标签: python list tuples

例如,假设一个给定的整数列表:

int_list = list(range(-10,10))
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

查找int_list中任何给定的两个值是否等于给定的int,比如2,最有效的方法是什么?

我今天早上在一次技术电话采访中被问到如何使用int_list的1亿件物品来高效处理这种情况(我絮絮叨叨,没有好的答案:/)。

我的第一个想法是:

from itertools import combinations
int_list = list(range(-10,10))
combo_list = list(combinations(int_list, 2))
desired_int = 4
filtered_tuples = list(filter(lambda x: sum(x) == desired_int, combo_list))
filtered_tuples
[(-5, 9), (-4, 8), (-3, 7), (-2, 6), (-1, 5), (0, 4), (1, 3)]

哪一项甚至不适用于range(-10000, 10000)

的范围

另外,有没有人知道一个很好的在线Python性能测试工具?

4 个答案:

答案 0 :(得分:3)

对于任何整数A,最多只有一个整数B,它们将加在一起,等于整数N。通过列表,执行算术以及进行成员资格测试以查看集合中是否有B似乎更容易。

int_list = set(range(-500000, 500000))
TARGET_NUM = 2

def filter_tuples(int_list, target):
    for int_ in int_list:
        other_num = target - int_
        if other_num in int_list:
            yield (int_, other_num)

filtered_tuples = filter_tuples(int_list, TARGET_NUM)

请注意,这会重复结果。例如。 (-2, 4)(4, -2)的单独回复。您可以通过更改功能来解决此问题:

def filter_tuples(int_list, target):
    for int_ in int_list:
        other_num = target - int_
        if other_num in int_list:
            set.remove(int_)
            set.remove(other_num)
            yield (int_, other_num)

答案 1 :(得分:3)

编辑:请参阅我的其他答案以获得更好的方法(有警告)。

  

最有效的方法是查找int_list中给定的两个值是否等于给定的int,比如说2?

我的第一个倾向是使用itertools模块combinations以及any的短切能力来做到这一点,但它可能比亚当&#39慢得多方法:

>>> import itertools
>>> int_list = list(range(-10,10))
>>> any(i + j == 2 for i, j in itertools.combinations(int_list, 2))
True

似乎对较大范围的反应相当:

>>> any(i + j == 2 for i, j in itertools.combinations(xrange(-10000,10000), 2))
True
>>> any(i + j == 2 for i, j in itertools.combinations(xrange(-1000000,1000000), 2))
True

在我的机器上大约需要10秒钟:

>>> any(i + j == 2 for i, j in itertools.combinations(xrange(-10000000,10000000), 2))
True

答案 2 :(得分:2)

使用数学的更直接的方法:

  

假设一个给定的整数列表:

     

int_list = list(范围(-10,10))... [ - , - 9,-8,-7,-6,-5,-4,-3,-2,   -1,0,1,2,3,4,5,6,7,8,9]

     

查找是否有任何给定的两个值的最有效方法是什么?   int_list sum等于给定的int,比如2? ......如何有效率   使用int_list,即1亿个项目来处理这个场景。

很明显,我们可以推导出我们可以对表格范围(-n,n)的整数范围应用单个参数n的要求,这意味着每个从负n到整数但不包括的整数积极的从那里可以清楚地看出,某个数字x是否是该范围内任意两个整数的总和。

任何这样的范围都可以简单地显示为包含一对与该范围内的任何数字相加并且超出它的n-1,因此搜索它的计算能力会浪费。

def x_is_sum_of_2_diff_numbers_in_range(x, n):
    if isinstance(x, int) and isinstance(n, int):
        return -(n*2) < x < (n - 1)*2
    else:
        raise ValueError('args x and n must be ints')

几乎立即计算:

>>> x_is_sum_of_2_diff_numbers_in_range(2, 1000000000000000000000000000)
True

测试边缘情况:

def main():
    print x_is_sum_of_2_diff_numbers_in_range(x=5, n=4) # True
    print x_is_sum_of_2_diff_numbers_in_range(x=6, n=4) # False
    print x_is_sum_of_2_diff_numbers_in_range(x=-7, n=4) # True
    print x_is_sum_of_2_diff_numbers_in_range(x=-8, n=4) # False

编辑:

因为我可以看到这个问题的更广义的版本(列表中可能包含任何给定的数字)是一个常见的版本,我可以看到为什么有些人对此有一种先入为主的方法,但我仍然坚持我的解释这个问题的要求,我认为这个答案是这个更具体案例的最佳方法。

答案 3 :(得分:0)

我原本以为任何依赖于列表上的双重嵌套迭代的解决方案(虽然内部循环被一个漂亮的Python函数隐藏)是O(n ^ 2)。

值得考虑对输入进行排序。对于任何合理的基于比较的排序,这将是O(n.lg(n)),其已经优于O(n ^ 2)。您可以使用基数排序或预排序(根据输入列表的范围进行排序)做得更好。

对输入进行排序后,找到一对总和为任意给定数字的数字是O(n)运算,因此总体复杂度为O(n.lg(n))。

在实践中,对于规定的“大量”元素,具有良好缓存行为的蛮力O(n ^ 2)算法(按顺序压缩数组)是否会胜过一个悬而未决的问题渐近更好的算法可以移动大量数据,但最终渐近复杂度较低的算法会获胜。