给定一个包含许多元素的列表,如何获得完美三元组的数量?

时间:2017-02-07 06:21:56

标签: python algorithm list

我尝试解决编程问题,在给定整数列表的情况下,找到完整三元组的数量[x, y, z]其中y % x == 0 and z % y == 0

例如,[1, 2, 3, 4, 5, 6]有三元组:[1, 2, 4][1, 2, 6][1, 3, 6],总共得到答案。

这是我到目前为止所做的:

def solution(l):
    l.sort()
    l.reverse()
    l_size = len(l)
    count = 0

    if len(l) < 3:
        return count

    for i in xrange(len(l) - 2):
        for j in xrange(i + 1, len(l) - 1):
            if l[i] % l[j] == 0:
                for k in xrange(j + 1, len(l)):
                    if l[j] % l[k] == 0:
                        count += 1

    return count

我的解决方案的问题是l的长度可能介于2和2000之间。因此,输入时间过长需要很长时间。

3 个答案:

答案 0 :(得分:2)

如果你创建所有可能除数的映射,然后计算有多少可能的除数有可能的除数,你可以更快。

from operator import itemgetter

def solution(l):
    l.sort(reverse=True)

    # The mapping will have each element as key and the possible divisors as value
    mapping = {}

    # Find all possible divisors for a number
    for idx, item in enumerate(l):
        # Use a set as value for faster lookups
        divisors = set()
        for other_item in l[idx+1:]:
            if item % other_item == 0:
                divisors.add(other_item)
        mapping[item] = divisors

    # Count the possibilities
    count = 0
    for z, ys in sorted(mapping.items(), key=itemgetter(0), reverse=True):
        for y in ys:
            count += len(mapping[y])

    return count

检查我在IPython中使用%timeit的时间:

vals = list(range(1, 2000))
assert solution(vals) == your_solution(vals)
%timeit solution(vals)         # 1 loop, best of 3: 652 ms per loop
%timeit your_solution(vals)    # 1 loop, best of 3: 1.64 s per loop
# niemmi's solution only give the same solution when reversed.
vals = vals[::-1]
%timeit niemmi_solution(vals)  # 1 loop, best of 3: 1.99 s per loop
%timeit niemmi_solution2(vals) # 1 loop, best of 3: 1.01 s per loop

答案 1 :(得分:2)

如果您只需要计数而不是实际三元组,则可以在 O(n ^ 2)时间内完成此操作。首先创建一个列表,指示列表中有多少其他数字可以均匀地划分数字。这需要 O(n ^ 2)时间。

然后迭代从最大值开始的数字以查找所有zy对,并为每对添加从第一步创建的列表中y的值到结果。这也需要 O(n ^ 2)时间。

def solution(l):
    divs = [0] * len(l)

    for i in range(len(l)):
        for j in range(i + 1, len(l)):
            if l[j] % l[i] == 0:
                divs[j] += 1

    result = 0
    for i in range(len(l) - 1, 1, -1):
        for j in range(i - 1, 0, -1):
            if l[i] % l[j] == 0:
                result += divs[j]

    return result

print(solution([1, 2, 3, 4, 5, 6]))
print(solution(list(range(1, 2000))))

输出:

3
40777

更新以下是另一个一次处理列表的解决方案:

def solution2(l):
    divs = [[0, 0] for _ in l]

    for i in range(len(l)):
        for j in range(i + 1, len(l)):
            if l[j] % l[i] == 0:
                divs[j][0] += 1
                divs[j][1] += divs[i][0]

    return sum(x[1] for x in divs)

答案 2 :(得分:-1)

ns = [1, 2, 3, 4, 5, 6]

from itertools import combinations

sum(1 for x, y, z in combinations(ns, 3) if y % x == 0 and z % y == 0)
Out[55]: 3

这确实需要一两分钟,绝对不是速度赢家

sum(1 for x, y, z in combinations(list(range(1, 2000)), 3) if y % x == 0 and z % y == 0)
Out[56]: 40777