我需要创建一个函数,给定一个正整数列表(可能有重复的整数),计算所有三元组(在列表中),其中第三个数字是第二个的倍数,第二个是多个第一个:
(相同的数字不能在一个三元组中使用两次,但可以被所有其他三元组使用)
例如,[3, 6, 18]
就是一个因为18
均匀地进入6
,并且均匀地进入3
。
所以给定[1, 2, 3, 4, 5, 6]
它应该找到:
[1, 2, 4] [1, 2, 6] [1, 3, 6]
并返回3
(它找到的三元组数)
我做了一些有效但功效不够的功能。是否有一些我不知道的数学概念可以帮助我更快地找到这些三元组?具有更好功能的模块?我不知道该搜索什么...
def foo(q):
l = sorted(q)
ln = range(len(l))
for x in ln:
if len(l[x:]) > 1:
for y in ln[x + 1:]:
if (len(l[y:]) > 0) and (l[y] % l[x] == 0):
for z in ln[y + 1:]:
if l[z] % l[y] == 0:
ans += 1
return ans
这个更快一点:
def bar(q):
l = sorted(q)
ans = 0
for x2, x in enumerate(l):
pool = l[x2 + 1:]
if len(pool) > 1:
for y2, y in enumerate(pool):
pool2 = pool[y2 + 1:]
if pool2 and (y % x == 0):
for z in pool2:
if z % y == 0:
ans += 1
return ans
这是我从你们所有人那里得到的帮助,但我必须做错事,因为它得到了错误的答案(尽管它真的很快):
def function4(numbers):
ans = 0
num_dict = {}
index = 0
for x in numbers:
index += 1
num_dict[x] = [y for y in numbers[index:] if y % x == 0]
for x in numbers:
for y in num_dict[x]:
for z in num_dict[y]:
print(x, y, z)
ans += 1
return ans
(39889
而不是40888
) - 哦,我不小心让索引var从1开始而不是0.它现在有效。
通过重新评估我需要它做什么,我找到了找到三元组数量的最佳方法。这种方法实际上并没有找到三元组,它只计算它们。
def foo(l):
llen = len(l)
total = 0
cache = {}
for i in range(llen):
cache[i] = 0
for x in range(llen):
for y in range(x + 1, llen):
if l[y] % l[x] == 0:
cache[y] += 1
total += cache[x]
return total
这是一个功能版本,可以解释思考过程(虽然因为垃圾邮件打印而不适合大型列表):
def bar(l):
list_length = len(l)
total_triples = 0
cache = {}
for i in range(list_length):
cache[i] = 0
for x in range(list_length):
print("\n\nfor index[{}]: {}".format(x, l[x]))
for y in range(x + 1, list_length):
print("\n\ttry index[{}]: {}".format(y, l[y]))
if l[y] % l[x] == 0:
print("\n\t\t{} can be evenly diveded by {}".format(l[y], l[x]))
cache[y] += 1
total_triples += cache[x]
print("\t\tcache[{0}] is now {1}".format(y, cache[y]))
print("\t\tcount is now {}".format(total_triples))
print("\t\t(+{} from cache[{}])".format(cache[x], x))
else:
print("\n\t\tfalse")
print("\ntotal number of triples:", total_triples)
答案 0 :(得分:4)
现在你的算法有O(N ^ 3)运行时间,这意味着每次你加倍初始列表的长度时,运行时间会增加8倍。
在最坏的情况下,你无法改善这一点。例如,如果你的数字都是2的连续幂,意味着每个数字除以每个数字都比它更重要,那么每三个数字都是一个有效的解决方案,所以打印出来的所有解决方案都会像你现在在做什么。
如果你有一个较低的“密度”数字来划分其他数字,你可以做的一件事就是搜索成对的数字而不是三元组。这将花费时间仅为O(N ^ 2),这意味着当您将输入列表的长度加倍时,运行时间会增加4倍。一旦你有一对数字列表,你可以用它来建立一个三元组列表。
# For simplicity, I assume that a number can't occur more than once in the list.
# You will need to tweak this algorithm to be able to deal with duplicates.
# this dictionary will map each number `n` to the list of other numbers
# that appear on the list that are multiples of `n`.
multiples = {}
for n in numbers:
multiples[n] = []
# Going through each combination takes time O(N^2)
for x in numbers:
for y in numbers:
if x != y and y % x == 0:
multiples[x].append(y)
# The speed on this last step will depend on how many numbers
# are multiples of other numbers. In the worst case this will
# be just as slow as your current algoritm. In the fastest case
# (when no numbers divide other numbers) then it will be just a
# O(N) scan for the outermost loop.
for x in numbers:
for y in multiples[x]:
for z in multiples[y]:
print(x,y,z)
可能有更快的算法,也可以利用除法的代数属性,但在你的情况下,我认为O(N ^ 2)可能足够快。
答案 1 :(得分:4)
关键见解是:
如果 a 划分 b ,则表示 a &#34;适合 b &#34; 。 如果 a 没有划分 c ,则表示&#34; a 不适合 c 强>&#34 ;. 如果 a 无法适应 c ,则 b 无法适应 c (想象如果< strong> b 符合 c ,因为 a 适合 b ,然后 a 适合所有适合 c 的 b ,所以 a 也必须符合 c ..(想想主要因子化等))
这意味着我们可以优化。如果我们将数字从最小到最大排序,首先从较小的数字开始。第一次迭代,从最小的数字开始为 a 如果我们将数字分为两组,分组 1 , a 分组, 2 分组 a < / strong>没有划分,然后我们知道 1 组中的数字不能划分 2 组中的数字,因为 2 组中没有数字将 a 作为一个因素。
所以,如果我们有[2,3,4,5,6,7],我们将从2开始并得到: [2,4,6]和[3,5,7] 我们可以在每个组上重复这个过程,分成更小的组。这表明一种算法可以更有效地计算三元组。这些组的速度非常快,这意味着它的效率应该非常接近输出的大小。
答案 2 :(得分:0)
这是迄今为止我能够提出的最佳答案。它速度快,但速度不够快。我还在发帖,因为我可能会放弃这个问题,并且不想忽略我已经取得的任何进展。
def answer(l):
num_dict = {}
ans_set = set()
for a2, a in enumerate(l):
num_dict[(a, a2)] = []
for x2, x in enumerate(l):
for y2, y in enumerate(l):
if (y, y2) != (x, x2) and y % x == 0:
pair = (y, y2)
num_dict[(x, x2)].append(pair)
for x in num_dict:
for y in num_dict[x]:
for z in num_dict[y]:
ans_set.add((x[0], y[0], z[0]))
return len(ans_set)