查找整个序列的数字总和的有效方法

时间:2016-04-09 14:33:00

标签: python algorithm

在下面的代码片段中,我找到了区间[a,b]

之间所有奇数的位数之和
def SumOfDigits(a, b):
    s = 0
    if a%2 == 0:
        a+=1
    if b%2 == 0:
        b-=1   
    for k in range(a,b+1,2):
        s+= sum(int(i) for i in list(str(k)))
    return s

有没有一种有效的方法来实现同样的目标? 任何模式,导致明确的公式。

我在https://oeis.org

中进行了搜索

2 个答案:

答案 0 :(得分:3)

避免转换到字符串和从字符串转换的所有开销,并直接使用数字本身:

.val()

答案 1 :(得分:2)

当然有一种模式。让我们看看在ab之间总结所有奇数和偶数的数字的问题。

例如:17到33

17  18  19    20  21  22  23  24  25  26  27  28  29    30  31  32  33

中间部分为您提供从0到9(45)加10次的所有数字之和。左边部分是7 + 8 + 9加3次1,右边是0 + 1 + 2 +的总和3加4次3。

中间部分可以包含几个十个块,例如,如果你计算17到63之间的范围,你可以得到40倍45加10个simes,其中的数字从2到5。

这为您提供了一个递归算法:

def ssum(n):
    return n * (n + 1) // 2

def dsum(a, b):
    res = 0

    if a == b:
        while a:
            res += a % 10
            a //= 10

    elif a < b:
        aa = a // 10
        bb = b // 10

        ra = a % 10
        rb = b % 10

        if aa == bb:
            res += ssum(rb) - ssum(ra - 1)
            res += (rb - ra + 1) * dsum(aa, bb)

        else:
            if ra > 0:
                res += 45 - ssum(ra - 1)
                res += (10 - ra) * dsum(aa, aa)
                aa += 1

            if rb < 9:
                res += ssum(rb)
                res += (rb + 1) * dsum(bb, bb)
                bb -= 1

            if aa <= bb:
                res += 45 * (bb - aa + 1)
                res += 10 * dsum(aa, bb) 

    return res

现在让我们将其扩展为仅包含奇数。 Adkust a以便它是偶数和b以便它是奇怪的。您的数字总和现在在偶数和奇数对上运行,其中even + 1 == odd。这意味着奇数的数字id比偶数更多,因为除了最后一个数字之外的所有数字都是相同的,最后一个奇数位比偶数数字多一个。

因此:

dsum(a, b) == oddsum + evensum

oddsum - evensum == (b - a + 1) // 2

对所有奇数的位数求和的函数是:

def oddsum(a, b):
    if a % 2: a -= 1
    if b % 2 == 0: b -= 1

    d = (b - a + 1) // 2

    return (dsum(a, b) + d) // 2

当我查看你关于OEIS的评论时,我注意到可以通过编写一个函数来简化算法,将所有数字中的数字从零加到n,然后计算差值{{1 }}。可能有更多的优化机会。