下一个更高的素数和回文数

时间:2013-12-18 05:54:20

标签: python algorithm data-structures palindrome

是否有任何关于从给定的int解决下一个更高的素数和回文数的建议。

这是我正在尝试的片段,但它有点慢,如果你有任何我可以测试的好算法,请建议。

#!/usr/bin/python                                                                                                                                            

def next_higher(n):
    while True:
        s = str(n)
        if not any([n % i == 0 \
            for i in range(2, int(n**0.5))]) and s == s[::-1]:
                return n
        n = n + 1

print next_higher(2004)
print next_higher(20)

输出:

10201
101 

在素数之前更新了回文的代码测试。比我以前的代码快得多。 我正在实施user2357112的建议。

  #!/usr/bin/python                                                                                                                                          

  def next_higher(n):
      while True:
          s = str(n)
          if s == s[::-1]:
              if not any([n % i == 0 \
                  for i in range(2, int(n**0.5))]):
                      return n
          n = n + 1

  print next_higher(2004111)
  print next_higher(2004)
  print next_higher(2004)
  print next_higher(20)

4 个答案:

答案 0 :(得分:5)

你可以做很多优化:

  • 与评论中建议的user2357 ..一样,首先测试回文率,然后检查数字是否为素数,因为素数检查更贵。
  • 一旦检查数字是否可被2整除,则无需检查偶数可分性。因此,您可以将其更改为[2] + range(3, int(n**0.5) + 1, 2)以仅检查2之后的奇数。(此外,您还需要执行sqrt + 1,就像我在评论中提到的那样)
  • 您应该使用()代替[][]首先生成完整的因子列表,然后才检查any。如果您使用(),它会创建一个生成器,因此只要找到True值就会停止,而不会计算整个列表。
  • 出于同样的原因,你也应该使用xrange代替rangexrange给出生成器,range给出一个列表)
  • 您可以使用Sieve of Eratosthenes算法显着缩短素数检查所需的时间。
  • 您还可以查看是否可以更快地进行回文检查。实际上,您可以跳过大量数字,而不是每次只执行+ 1

除了最后两个,这是一个包含大多数优化的版本:

def next_higher(n):
    if n % 2 == 0:
        n = n - 1
    while True:
        n = n + 2
        s = str(n)
        if s == s[::-1]:
            if not any((n % i == 0 for i in xrange(3, int(n**0.5) + 1, 2))):
                return n

我相信这应该是相当快的。但是如果你愿意的话,你可以进行最后2次优化,使其更快。

答案 1 :(得分:2)

除了已经提出的建议外,

我建议你先得到第一个比给定整数高的回文数。

您可以尝试向外匹配中心数字。

此外,您应该只检查具有奇数位数的数字,因为如果数字具有偶数位数并且它是回文数,那么它将始终被11整除并且不能是素数。

一旦你得到第一个具有奇数位数并且刚好高于当前数字的回文数,请测试它的素数并找到高于此值的下一个回文数。

您可以通过递增中心数字来完成此操作。

继续这样做直到它翻到零。在这种情况下,开始递增两个相邻的数字。

继续,直到你到达一个素数。

答案 2 :(得分:2)

我尝试优化回文检查,即寻找奇怪的回文。 由于第一个数字应该是奇数,我专注于那个部分。 这是下面的代码,假设大于1位数。

def next_odd_palindrome(n):
  """to check the next odd palindrome number"""
  if n%2==0:
    n=n-1
  while True:
    n=n+2
    s = str(n)
    if int(s[0])%2==0:
      n = int(str(int(s[0])+1)+ s[1:])
      s = str(n)
    if s==s[::-1]:
      return n

如果有任何错误,请告诉我。

答案 3 :(得分:2)

为了好玩,我实施了Hari Shankar和Abhishek Bansal的所有优化。

它首先发现较高的奇数长度回文,然后以保持其回文性的方式增加回文。然后使用Sieve方法在开头计算的素数检查每个数字。

在我的计算机中,这可以在1秒内处理最多n=10^14(如果你增加CACHE大小可以更高)= D

primes = []
CACHE = int(10**7) # Cache size for Sieve

# Custom class for immediate printing of output
import sys
class Unbuf:
    def __init__(self,stream):
        self.stream = stream

    def write(self,data):
        self.stream.write(data)
        self.stream.flush()
sys.stdout = Unbuf(sys.stdout)

def sieve():
    global primes
    is_prime = [False,False]+([True]*(CACHE-1))
    for i in xrange(2,int(CACHE**0.5)):
        if is_prime[i]:
            is_prime[i*i::i] = [False]*((CACHE-i*i+i)/i)
    primes = [num for num, bool_prime in enumerate(is_prime) if bool_prime]

def is_prime(n):
    """Checks whether n is prime"""
    global primes
    if n<2:
        return False
    if n==2:
        return True
    for prime in primes:
        if prime>n**0.5+1:
            return True
        if n%prime==0:
            return False
    # For the case that the number is bigger than the square of our largest prime
    for num in xrange(primes[-1]+2,n**0.5+1,2):
        if n%num==0:
            return False
    return True

def next_higher_odd_length_palindrome(n):
    n = str(n)
    if len(n)%2==0: # Even length, take the smallest odd length (10(00)*1)
        n = '1'+('0'*(len(n)-1))+'1'
    else:
        middle_idx = len(n)/2
        left = int(n[:middle_idx+1])
        left_cmp = n[middle_idx::-1]
        right_cmp = n[middle_idx:]
        # If mirroring left part to right part
        # makes the number smaller or equal, then
        if right_cmp>=left_cmp:
            # Increase the left half number
            left = left+1
        # Mirror left part to the right part
        n = str(left)+str(left)[-2::-1]
    return n

def next_higher(n):
    if n<=1:
        return 2
    # Ensure the number is a palindrome of odd length
    n = next_higher_odd_length_palindrome(n)
    while True:
        if is_prime(int(n)):
            return int(n)
        n = next_higher_odd_length_palindrome(n)
        if int(n[0])%2==0:
            new_lead = str(int(n[0])+1)
            n = new_lead+n[1:-1]+new_lead

import time
print 'Sieving...',
start_time = time.time()
sieve()
print 'Done in %.3fs' % (time.time() - start_time)
print next_higher(2004111)
print next_higher(2004)
print next_higher(20)
while True:
    n = int(raw_input('Enter n: '))
    start_time = time.time()
    result = next_higher(n)
    print 'Next higher prime palindrome: %d (calculated in %.3fs)' % (result, time.time() - start_time)

在我的计算机中提供此输出:

Sieving... Done in 1.444s
3007003
10301
101
Enter n: 1999999999
Next higher prime palindrome: 10000500001 (calculated in 0.004s)
Enter n: 1999999999999
Next higher prime palindrome: 3000002000003 (calculated in 0.051s)
Enter n: 1000000000000
Next higher prime palindrome: 1000008000001 (calculated in 0.030s)
Enter n: