[英]Efficient way to find sum of digits of an entire sequence
In the following code snippet I am finding the sum of digits of all odd number between the interval [a,b] 在下面的代码片段中,我找到了区间[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
Is there an efficient way to accomplish the same? 有没有一种有效的方法来实现同样的目标? Any patterns, which is leading to a clear cut formula.
任何图案,这导致明确的公式。
I did search in https://oeis.org 我在https://oeis.org上搜索过
Avoid all the overhead of conversion to and from strings and work directly with the numbers themselves: 避免转换到字符串和从字符串转换的所有开销,并直接使用数字本身:
def SumOfDigits(a, b):
result = 0
for i in range(a + (not a % 2), b + 1, 2):
while i:
result += i % 10
i //= 10
return result
Of course there is a pattern. 当然有一种模式。 Let's look at the problem of summing up the digitsums of all – odd and even – numbers between
a
and b
inclusively. 让我们来看看总结
a
和b
之间所有奇数和偶数的数字的问题。
For example: 17 to 33 例如:17到33
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
The middle section gives you the sum of all digits from 0 to 9 (45) plus ten times 2. The left section is 7 + 8 + 9 plus three times 1 and the right the sum of 0 + 1 + 2 + 3 plus four times 3. 中间部分为您提供从0到9(45)加10次的所有数字的总和2.左侧部分是7 + 8 + 9加3次1,右侧是0 + 1 + 2 + 3加4的总和次3。
The middle section can comprise several blocks of ten, for example if you calculate the range between 17 and 63, you get 40 times 45 plus ten simes the the digitsums from 2 to 5. 中间部分可以包含几个十个块,例如,如果你计算17到63之间的范围,你可以得到40倍45加10个simes,其中digitums从2到5。
This gives you a recursive algorithm: 这给你一个递归算法:
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
Now let's extend this to include only odd numbers. 现在让我们将其扩展为仅包含奇数。 Adkust
a
so that it is even and b
so that it is odd. Adkust
a
,它是偶数和b
所以它是奇怪的。 Your sum of digit sums now runs over pairs of even and odd numbers, where even + 1 == odd
. 你的数字和的总和现在在偶数和奇数对上运行,其中
even + 1 == odd
。 That means that the digitsum of the odd number id one more than the even number, because all except the last digits are the same and the last odd digit is one more than the even digit. 这意味着奇数的数字id比偶数更多,因为除了最后的数字之外的所有数字都是相同的,并且最后的奇数数字比偶数数字多一个。
Therefore: 因此:
dsum(a, b) == oddsum + evensum
and: 和:
oddsum - evensum == (b - a + 1) // 2
The function to sum the digitsums of all odd numbers is then: 然后,将所有奇数的位数相加的函数为:
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
When I looked at your comment about OEIS, I've noticed that the algorithm can probably be simplified by writing a function to sum the digits from all numbers from zero to n
and then calculate the difference dsum(b) - dsum(a)
. 当我查看你关于OEIS的评论时,我注意到可以通过编写一个函数来简化算法,将所有数字中的数字从0加到
n
,然后计算差值dsum(b) - dsum(a)
。 There are probably more opportunities for optimisation. 可能有更多的优化机会。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.