简体   繁体   English

如何计算没有。 大量间隔的palindroms?

[英]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 and n ? 0n之间有给定属性的数字是多少?

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) ),对于负ncountTo(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 + 1d = 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是其中之一

  • palindromes with fewer than 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) ,或者
  • palindromes with exactly 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] ,我们可以自由选择mc[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 == 310**(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.

相关问题 如何计算 2 的一个大数的幂模另一个大数? - How to calculate 2 to the power of a large number modulo another large number? 如何计算大量记录的相关性? - How to calculate correlation on large number of records? 如何在Python中快速计算大量向量的余弦相似度? - How to quickly calculate cosine similarity for large number of vectors in Python? Python计算大量错误 - Python calculate large number wrong 如何计算一个非常非常大的数字并将其写入 python 中的文件? - How to calculate and write a very, very large number to a file in python? 如何计算编号从当前周到给定周的周数? - How to calculate the no. of Weeks from present week to given week? 如何检查某个数字是否在某个区间内 - How to check if a number is in a interval 如何计算日期时间对象之间的差异并根据天数获取时间间隔 - How to calculate difference between datetime objects and get a time interval based on the number of days 计算大量序列的成对差异矩阵? - Calculate matrix of pairwise differences for large number of sequences? 处理大数以计算组合数 - Handling large numbers to calculate the number of combinations
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM