在Python中,计算整数列表中唯一的乘法和加法对的数量的有效方法是什么?

时间:2018-12-17 22:22:00

标签: python python-3.x algorithm

给定一个排序数组A = [n,n + 1,n + 2,... n + k]个元素,我试图计算乘法对和加法对的唯一数目,以使条件xy> = x + y是满意的。其中x和y是列表的索引,而y> x。

这是我使用朴素蛮力方法的最低工作示例:

def minimum_working_example(A):
    A.sort()
    N = len(A)
    mpairs = []
    x = 0
    while x < N:
        for y in range(N):
            if x<y and (A[x]*A[y])>=(A[x]+A[y]):
                mpairs.append([A[x], A[y]])               
            else:
                continue    
        x+=1
    return len(mpairs)  

A = [1,2,3,4,5]
print(minimum_working_example(A))
#Output = 6, Unique pairs that satisfy xy >= x+y: (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)

但是,对于大型列表,此方法的时间复杂度很高。

存在哪些排序或搜索算法可让我实施更有效的解决方案?

4 个答案:

答案 0 :(得分:2)

这个问题有一个封闭形式的数学解决方案,但是如果您希望用编程语言来实现,则只需从列表中查找所有唯一的数字对,然后计算满足您要求的数字。 itertools.combinations是您的朋友在这里:

import itertools

A = [1,2,3,4,5]
pairs = []
for x, y in itertools.combinations(A, 2):
    if x*y >= x + y:
        pairs.append((x,y))

输出

[(2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]

答案 1 :(得分:2)

基本代数...根据另一个变量求解一个变量:

xy >= x + y
xy - y >= x
y(x-1) >= x

现在,如果您的元素都是正整数,您将得到

if x == 1, no solution
if x == 2, y >= 2
else x > 2
y >= x/(x-1)

在最后一种情况下,x /(x-1)是1到2之间的分数;再次,

y >= 2

解决不平等问题。

这为您提供了在 O(1)时间内轻松访问的解决方案;如果您需要配对,那么您会受到打印的限制,这是 O(n ^ 2)时间。

答案 2 :(得分:1)

因此,使用x*y >= x+y如果同时都是(我的原始评论有误)xy>=2的事实(请参阅@Prune的答案以获取详细信息),那么您最好将01从列表中删除,因为它们不会配对。

因此,现在假设所有数字或>=2并且您拥有k(例如,如果您有k,则在以下操作中将k-1替换为n=1 ),所有可能的对都将满足您的条件。 k元素之间的对数是众所周知的公式k*(k-1)/2(如果您不知道,可以用Google搜索)。无论您拥有k的什么值(除非您开始研究大数字),计算该数字的时间基本上是相同的(一次乘法,一次除法),因此复杂度为O(1)。

这假设您的整数是正数,如果不是,则公式会稍微复杂一些,但仍然可以作为封闭形式的解决方案。

答案 3 :(得分:0)

如果您需要更多的数学解,请考虑classes = ['data_one', 'data_two', 'data_three'] result = {} for class_value in classes: try: result[class_value] = soup.find('div', class_=class_value).get_text() except AttributeError: result[class_value] print(result) 没有xy > x+y的解。否则,您可以将其代数化为y=1。现在,如果我们有两个连续的整数,然后将较大的整数除以较小的整数,则可以得到2(如果y = 2),也可以得到1到2之间的分数。请注意,x必须大于此y /(y-1)商,但还必须小于y。如果y = 2,则我们的正整数列表中唯一可能的x值必须为1,在这种情况下将不存在匹配项,因为1不大于2/1。因此,这全部简化为“对于列表中的每个数字y,对[2,y)范围内的所有值x进行计数。”如果您进行数学运算,则应该加上1 + 2 + 3 + ... + k,即x > y/(y-1)。同样,我们假设n和k是正整数;当考虑n <= 0的情况时,可以得出一个稍微复杂的公式。

但是假设您确实想使用蛮力方法,而又不做任何数学推理来寻找另一种方法:我尝试了几种变体,这是基于以下方法的一种更快的解决方案。

  • 您说列表已经排序,所以我放弃了排序功能。
  • 同样,不需要“ else:continue”,因此为简单起见,我将其删除。
  • 与其循环遍历所有x和y值,然后检查x
  • 您可以使用k(k+1)/2生成列表itertools中所有数字的唯一对
  • 如果您最终真的只关心A列表的长度,而不关心数字对本身,那么您可以沿途对数字进行计数而不是存储它们。否则,您可能会在N值较高时耗尽内存。
  • 在x(y-1)-y> 0的等效测试下,我得到的结果更快。比x(y-1)> y还要多。

这就是我所拥有的:

pairs

所有时间都在这里

def example4(A):
    mpair_count = 0
    for pair in itertools.combinations(A, 2):
        if pair[0]*(pair[1]-1) - pair[1] > 0:
            mpair_count += 1
    return mpair_count

结果:

from timeit import default_timer as timer
import itertools

def minimum_working_example(A):
    A.sort()
    N = len(A)
    mpairs = []
    x = 0
    while x < N:
        for y in range(N):
            if x<y and (A[x]*A[y])>=(A[x]+A[y]):
                mpairs.append([A[x], A[y]])
            else:
                continue
        x+=1
    return len(mpairs)

# Cutting down the range
def example2(A):
    N = len(A)
    mpairs = []
    x = 0
    while x < N:
        for y in range(x+1,N):
            if (A[x]*A[y])>=(A[x]+A[y]):
                mpairs.append([A[x], A[y]])
        x += 1
    return len(mpairs)

# Using itertools
def example3(A):
    mpair_count = 0
    for pair in itertools.combinations(A, 2):
        if pair[0]*pair[1] > sum(pair):
            mpair_count += 1
    return mpair_count

# Using itertools and the different comparison
def example4(A):
    mpair_count = 0
    for pair in itertools.combinations(A, 2):
        if pair[0]*(pair[1]-1) - pair[1] > 0:
            mpair_count += 1
    return mpair_count

# Same as #4, but slightly different
def example5(A):
    mpair_count = 0
    for pair in itertools.combinations(A, 2):
        if pair[0]*(pair[1]-1) > pair[1]:
            mpair_count += 1
    return mpair_count

A = range(1,5000)
start = timer()
print(minimum_working_example(A))
end = timer()
print(end - start)

start = timer()
print(example2(A))
end = timer()
print(end - start)


start = timer()
print(example3(A))
end = timer()
print(end - start)

start = timer()
print(example4(A))
end = timer()
print(end - start)

start = timer()
print(example5(A))
end = timer()
print(end - start)