加快在给定范围内找到倍数的算法

时间:2015-05-05 04:12:25

标签: python algorithm

我很难理解如何加速我的算法,该算法将给定范围内的倍数相加。这是针对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,任何想法的人更快?

1 个答案:

答案 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

我们有答案!

相关问题