我很难理解如何加速我的算法,该算法将给定范围内的倍数相加。这是针对codewars.com上的问题,这里是问题的链接 codewars link
这里是代码,我将解释底部发生的事情
import itertools
def solution(number):
return multiples(3, number) + multiples(5, number) - multiples(15, number)
def multiples(m, count):
l = 0
for i in itertools.count(m, m):
if i < count:
l += i
else:
break
return l
print solution(50000000) #takes 41.8 seconds
#one of the testers takes 50000000000000000000000000000000000000000 as input
# def multiples(m, count):
# l = 0
# for i in xrange(m,count ,m):
# l += i
# return l
所以基本上问题是要求用户返回一个数字中所有3和5的倍数之和。以下是测试人员。
test.assert_equals(solution(10), 23)
test.assert_equals(solution(20), 78)
test.assert_equals(solution(100), 2318)
test.assert_equals(solution(200), 9168)
test.assert_equals(solution(1000), 233168)
test.assert_equals(solution(10000), 23331668)
我的程序在获得正确答案方面没有问题。输入很大时会出现问题。传递50000000这样的数字时,返回答案需要40秒以上。我要求采取的其中一项投入是500亿,超过100亿,这是一个巨大的数字。这也是我使用itertools.count()
的原因我在第一次尝试中尝试使用xrange
,但范围无法处理大于c类型的数字。我知道问题的最慢部分是倍数方法......但是它仍然比我第一次尝试使用列表理解并检查是否i % 3 == 0 or i % 5 == 0
,任何想法的人更快?
答案 0 :(得分:4)
对于大数字,此解决方案应该更快。
def solution(number):
number -= 1
a, b, c = number // 3, number // 5, number // 15
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
return 3*asum + 5*bsum - 15*csum
<强>解释强>
从1到n采取任何顺序:
1, 2, 3, 4, ..., n
它的总和将始终由公式n(n+1)/2
给出。如果您认为表达式(1 + n) / 2
只是计算此特定数字序列的平均值或Arithmetic mean的快捷方式,则可以轻松证明这一点。因为average(S) = sum(S) / length(S)
,如果你取任何数字序列的平均值并乘以序列的长度,你得到序列的总和。
如果我们给出一个数字n,并且我们想要一些给定k的倍数的总和达到n,包括n,我们想找到总和:
k + 2k + 3k + 4k + ... xk
其中xk是k的最大倍数,小于或等于n。现在注意这个总和可以考虑到:
k(1 + 2 + 3 + 4 + ... + x)
我们已经给了k,所以现在我们需要找到的是x。如果x被定义为最高数,你可以将k乘以得到小于或等于n的自然数,那么我们可以通过使用Python的整数除法得到数x:
n // k == x
一旦找到x,我们就可以使用以前的公式找到任何给定k的倍数与给定n的总和:
k(x(x+1)/2)
我们给出的三个k是3,5和15。
我们在这一行中找到了x:
a, b, c = number // 3, number // 5, number // 15
在此行中计算其倍数的总和,最多为n:
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
最后,在这一行中将它们的求和乘以k:
return 3*asum + 5*bsum - 15*csum
我们有答案!