[英]How to calculate no. of palindroms in a large number interval?
I want to calculate how many numbers are palindrome in large interval data say 10^15
我想计算在大间隔数据中有多少数是回文数据
10^15
My simple code (python) snippet is: 我的简单代码(python)代码段是:
def count_palindromes(start, end):
count = 0
for i in range(start, end + 1):
if str(i) == str(i)[::-1]:
count += 1
return count
start = 1000 #some initial number
end = 10000000000000 #some other large number
if __name__ == "__main__":
print count_palindromes(start, end)
Its a simple program which checks each number one by one. 它是一个简单的程序,逐个检查每个数字。 Its vary time consuming and takes a lot of computer resources.
它耗费大量时间并占用大量计算机资源。
Is there any other method/technique by which we can count Palindrome numbers? 有没有其他方法/技术我们可以计算Palindrome数字? Any Algorithm to use for this?
用于此的任何算法?
I want to minimize time taken in producing the output. 我想尽量减少产生输出的时间。
When you want to count the numbers having some given property between two limits, it is often useful to solve the somewhat simpler problem 当您想要计算具有两个限制之间某些给定属性的数字时,解决稍微简单的问题通常很有用
How many numbers with the given property are there between
0
andn
?在
0
和n
之间有给定属性的数字是多少?
Keeping one limit fixed can make the problem significantly simpler to tackle. 保持一个限制可以使问题明显更容易解决。 When the simpler problem is solved, you can get the solution to the original problem with a simple subtraction:
当更简单的问题得到解决时,您可以通过简单的减法得到原始问题的解决方案:
countBetween(a,b) = countTo(b) - countTo(a)
or countTo(b ± 1) - countTo(a ± 1)
, depending on whether the limit is included in countTo
and which limits shall be included in countBetween
. 或
countTo(b ± 1) - countTo(a ± 1)
这取决于限制是否被包括在countTo
和限制应包括在countBetween
。
If negative limits can occur (not for palindromes, I presume), countTo(n)
should be <= 0
for negative n
(one can regard the function as an integral with respect to the counting measure). 如果可能出现负限制(不是对于回文,我
countTo(n)
),对于负n
, countTo(n)
应该<= 0
(可以将该函数视为相对于计数测量的积分)。
So let us determine 所以让我们来决定
palindromes_below(n) = #{ k : 0 <= k < n, k is a palindrome }
We get more uniform formulae for the first part if we pretend that 0 is not a palindrome, so for the first part, we do that. 如果我们假设0不是回文,我们会得到第一部分更均匀的公式,所以对于第一部分,我们这样做。
Part 1: How many palindromes with a given number d
of digits are there? 第1部分:有多少个具有给定数字
d
位数的回文?
The first digit cannot be 0
, otherwise it's unrestricted, hence there are 9 possible choices ( b-1
for palindromes in an arbitrary base b
). 第一个数字不能为
0
,否则它不受限制,因此有9种可能的选择( b-1
用于任意碱基b
回文)。
The last digit is equal to the first by the fact that it shall be a palindrome. 最后一个数字等于第一个数字,它应该是一个回文。
The second digit - if d >= 3
- can be chosen arbitrarily and independently from the first. 第二个数字 - 如果
d >= 3
- 可以任意选择并独立于第一个数字。 That also determines the penultimate digit. 这也决定倒数第二位。
If d >= 5
, one can also freely choose the third digit, and so on. 如果
d >= 5
,也可以自由选择第三个数字,依此类推。
A moment's thought shows that for d = 2*k + 1
or d = 2*k + 2
, there are k
digits that can be chosen without restriction, and one digit (the first) that is subject to the restriction that it be non-zero. 片刻的思考表明,对于
d = 2*k + 1
或d = 2*k + 2
,有k
数字可以不受限制地选择,并且一个数字(第一个)受限于它是非-零。 So there are 所以有
9 * 10**k
d
-digit palindromes then ( (b-1) * b**k
for base b
). d
回文然后( (b-1) * b**k
为基础b
)。
That's a nice and simple formula. 这是一个很好的简单公式。 From that, using the formula for a geometric sum, we can easily obtain the number of palindromes smaller than 10 n (that is, with at most
n
digits): 由此,使用几何和的公式,我们可以很容易地获得小于10 n的回文数(即,最多
n
数字):
if n
is even, the number is 如果
n
是偶数,则数字是
n/2-1 n/2-1 2 * ∑ 9*10**k = 18 * ∑ 10**k = 18 * (10**(n/2) - 1) / (10 - 1) = 2 * (10**(n/2) - 1) k=0 k=0
if n
is odd, the number is 如果
n
是奇数,则数字为
2 * (10**((n-1)/2) - 1) + 9 * 10**((n-1)/2) = 11 * (10**((n-1)/2) - 2 2 *(10 **((n-1)/ 2) - 1)+ 9 * 10 **((n-1)/ 2)= 11 *(10 **((n-1)/ 2) - 2
(for general base b
, the numbers are 2 * (b**(n/2) - 1)
resp. (b+1) * b**((n-1)/2) - 2
). (对于一般基数
b
,数字是2 * (b**(n/2) - 1)
或(b+1) * b**((n-1)/2) - 2
)。
That's not quite as uniform anymore, but still simple enough: 那不再那么统一,但仍然很简单:
def palindromes_up_to_n_digits(n):
if n < 1:
return 0
if n % 2 == 0:
return 2*10**(n//2) - 2
else:
return 11*10**(n//2) - 2
(remember, we don't count 0 yet). (记住,我们还不算0)。
Now for the remaining part. 现在剩下的部分了。 Given
n > 0
with k
digits, the palindromes < n
are either 给定
n > 0
且有k
数字,回文< n
是其中之一
k
digits, there are palindromes_up_to_n_digits(k-1)
of them, or k
位的palindromes_up_to_n_digits(k-1)
,有palindromes_up_to_n_digits(k-1)
,或者 k
digits that are smaller than n
. n
k
数字的回文。 So it remains to count the latter. 因此,仍需要计算后者。
Part 2: 第2部分:
Let m = (k-1)//2
and 设
m = (k-1)//2
和
d[1] d[2] ... d[m] d[m+1] ... d[k]
the decimal representation of n
(the whole thing works with the same principle for other bases, but I don't explicitly mention that in the following), so n
的十进制表示(整个事情与其他基础的原理相同,但我没有在下面明确提到),所以
k
n = ∑ d[j]*10**(k-j)
j=1
For each 1 <= c[1] < d[1]
, we can choose the m
digits c[2], ..., c[m+1]
freely to obtain a palindrome 对于每
1 <= c[1] < d[1]
,我们可以自由选择m
位c[2], ..., c[m+1]
来获得回文
p = c[1] c[2] ... c[m+1] {c[m+1]} c[m] ... c[2] c[1]
(the digit c[m+1]
appears once for odd k
and twice for even k
). (数字
c[m+1]
出现一次奇数k
和两次甚至k
)。 Now, 现在,
c[1]*(10**(k-1) + 1) <= p < (c[1] + 1)*10**(k-1) <= d[1]*10**(k-1) <= n,
so all these 10**m
palindromes (for a given choice of c[1]
!) are smaller than n
. 因此所有这些
10**m
回文(对于给定的c[1]
选择!)都小于n
。
Thus there are (d[1] - 1) * 10**m
k
-digit palindromes whose first digit is smaller than the first digit of n
. 因此,存在
(d[1] - 1) * 10**m
k
数字回文,其第一个数字小于n
的第一个数字。
Now let us consider the k
-digit palindromes with first digit d[1]
that are smaller than n
. 现在让我们考虑一个小于
n
第一个数字d[1]
的k
数字回文。
If k == 2
, there is one if d[1] < d[2]
and none otherwise. 如果
k == 2
,如果d[1] < d[2]
一个,否则没有。 If k >= 3
, for each 0 <= c[2] < d[2]
, we can freely choose the m-1
digits c[3] ... c[m+1]
to obtain a palindrome 如果
k >= 3
,对于每个0 <= c[2] < d[2]
,我们可以自由选择m-1
个数位c[3] ... c[m+1]
来获得回文
p = d[1] c[2] c[3] ... c[m] c[m+1] {c[m+1]} c[m] ... c[3] c[2] d[1]
We see p < n
: 我们看到
p < n
:
d[1]*(10**(k-1) + 1) + c[2]*(10**(k-2) + 10)
<= p < d[1]*(10**(k-1) + 1) + (c[2] + 1)*(10**(k-2) + 10)
<= d[1]*(10**(k-1) + 1) + d[2]*(10**(k-2) + 10) <= n
(assuming k > 3
, for k == 3
replace 10**(k-2) + 10
with 10). (假设
k > 3
,对于k == 3
将10**(k-2) + 10
替换为10)。
So that makes d[2]*10**(m-1)
k
-digit palindromes with first digit d[1]
and second digit smaller than d[2]
. 这样得到
d[2]*10**(m-1)
k
-digit回文,第一个数字d[1]
和第二个数字小于d[2]
。
Continuing, for 1 <= r <= m
, there are 继续,对于
1 <= r <= m
,有
d[m+1]*10**(m-r)
k
-digit palindromes whose first r
digits are d[1] ... d[r]
and whose r+1
st digit is smaller than d[r+1]
. k
-数位回文其第一r
数字被d[1] ... d[r]
和其r+1
ST位数小于d[r+1]
。
Summing up, there are 总结一下,有
(d[1]-1])*10**m + d[2]*10**(m-1) + ... + d[m]*10 + d[m+1]
k
-digit palindromes that have one of the first m+1
digits smaller than the corresponding digit of n
and all preceding digits equal to the corresponding digit of n
. k
-digit回文,其中第一个m+1
数字之一小于n
的相应数字,所有在前数字等于n
的相应数字。 Obviously, these are all smaller than n
. 显然,这些都小于
n
。
There is one k
-digit palindrome p
whose first m+1
digits are d[1] .. d[m+1]
, we must count that too if p < n
. 有一个
k
digit回文p
其第一个m+1
位是d[1] .. d[m+1]
,如果p < n
,我们也必须计算。
So, wrapping up, and now incorporating 0 too, we get 所以,结束,现在也加入0,我们得到了
def palindromes_below(n):
if n < 1:
return 0
if n < 10:
return n # 0, 1, ..., n-1
# General case
dec = str(n)
digits = len(dec)
count = palindromes_up_to_n_digits(digits-1) + 1 # + 1 for 0
half_length = (digits-1) // 2
front_part = dec[0:half_length + 1]
count += int(front_part) - 10**half_length
i, j = half_length, half_length+1
if digits % 2 == 1:
i -= 1
while i >= 0 and dec[i] == dec[j]:
i -= 1
j += 1
if i >= 0 and dec[i] < dec[j]:
count += 1
return count
Since the limits are both to be included in the count for the given problem (unless the OP misunderstood), we then have 由于限制都要包含在给定问题的计数中(除非OP被误解),我们就可以了
def count_palindromes(start, end):
return palindromes_below(end+1) - palindromes_below(start)
for a fast solution: 快速解决方案:
>>> bench(10**100,10**101-1)
900000000000000000000000000000000000000000000000000 palindromes between
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
and
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
in 0.000186920166016 seconds
Actually, it's a problem for Google Codejam (which I'm pretty sure you're not supposed to get outside help on) but alas, I'll throw in my 2 cents. 实际上,对于Google Codejam来说这是一个问题(我很确定你不应该得到外面的帮助)但是,唉,我会投入2美分。
The idea I came up with (but failed to implement) for the large problem was to precompile (generated at runtime, not hardcoded into the source) a list of all palindromic numbers less than 10^15
(there's not very many, it takes like ~60 seconds) then find out how many of those numbers lie between the bounds of each input. 我想出的大问题(但未能实现)的想法是预先编译(在运行时生成,而不是硬编码到源代码中)所有回文数小于
10^15
(不是很多,它需要像然后找出这些数字中有多少位于每个输入的边界之间。
EDIT: This won't work on the 10^100
problem, like you said, that would be a mathematical solution (although there is a pattern if you look, so you'd just need an algorithm to generate all numbers with that pattern) 编辑:这不会对
10^100
问题起作用,就像你说的那样,这将是一个数学解决方案(虽然如果看起来有一个模式,所以你只需要一个算法来生成具有该模式的所有数字)
I presume this is for something like Project Euler... my rough idea would be to generate all numbers up to half the length of your limit (like, if you're going to 99999, go up to 99). 我认为这是像Project Euler这样的东西...我的粗略想法是生成所有数字,最多可达到限制长度的一半(例如,如果你要去99999,最多可以达到99)。 Then reverse them, append them to the unreversed one, and potentially add a digit in the middle (for the numbers with odd lengths).
然后反转它们,将它们附加到未反转的那个,并可能在中间添加一个数字(对于具有奇数长度的数字)。 You'll might have to do some filtering for duplicates, or weird ones (like if you had a zero at the beginning of the number or sommat) but that should be a lot faster than what you were doing.
您可能需要对重复项进行一些过滤,或者对于重复项进行过滤(例如,如果您在数字或sommat的开头有零),那么这应该比您正在进行的操作快得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.