我尝试解决编程问题,在给定整数列表的情况下,找到完整三元组的数量[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之间。因此,输入时间过长需要很长时间。
答案 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)时间。
然后迭代从最大值开始的数字以查找所有z
,y
对,并为每对添加从第一步创建的列表中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