项目Euler#35:测试偶数整数是否在整数内部的更好方法

时间:2012-11-08 05:48:52

标签: python

问题:迭代一个整数并在其中找到其他整数的最佳方法是什么,然后如果它包含它们则扔掉那个整数?

长版:

我一直在研究我的Python技能,试图为Project Euler的问题提供有效的解决方案。在经历了大约20个问题后,我发现虽然我可以解决问题,但我的解决方案往往不够优雅和笨重(即丑陋和缓慢)。问题的结构方式,我认为我需要学习一些更好的解决方案,因为更复杂的东西会加剧这些低效率。

无论如何,今天我正在研究问题35,它要求所有低于1,000,000的循环素数。我已经制作了一份低于1,000,000的所有素数的列表,我建立了一个小框架,用于吐出下面这些素数的排列,我计划测试其中的每一个素数:

def number_switcher(number):
  number = [num for num in str(number)]
  numlist = [''.join(num) for num in list(itertools.permutations(number))]
  return [int(num) for num in numlist]

所有素数上运行此项,然后测试每种可能的素数排列,正如您所能想象的那样,无法解决问题。

然后我突然意识到,在我开始运行排列之前,我可以扔掉所有数字中的数字(假设它们长于一位数)或者其中包含五位数的数字。

这是我真正迷失的地方。虽然看起来很简单,但是经过两天的尝试后,我无法弄清楚如何丢弃任何带有偶数或5位数的多位数字。

这是我尝试的(假设所有素数低于1,000,000的名单在这里称为“素数”):

 [num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable

然后我尝试了以下内容:

for prime in primes:
  if '0' in str(prime):
    primes.remove(prime)

>>>>len(primes)
4264

这使我的素数列表减半。好的,所以也许我在正确的轨道上,我只需要一个丑陋的“if'0'在str(素数)或者如果'2'在str(素数),”等等。

但是这里有一个奇怪的事情:当我检查我的'素数'列表时,它仍然有'0'的素数。在新的素数列表上再次运行相同的东西,我得到以下结果:

 for prime in primes:
   if '0' in str(prime):
     primes.remove(prime)
>>>>len(primes)
4026

......结果再次落到:

>>>>len(primes)
3892
....
3861 # again
....
3843 #and again

也许我在这里遗漏了一些明显的东西,但似乎首先if-test应该找到任何带有'0'的素数并删除所有素数?

最后,我也尝试了以下内容,这看起来很糟糕,因为它在str整数列车轨道上来回无意义地跳跃,但它似乎只是必须工作:

for num in primes:
  for d in str(num):
    if (int(d) % 2 == 0 or int(d) == 5):
      primes.remove(num)   # doesn't work: ValueError: list.remove(x): x not in list 
    else:
      pass

我觉得我不应该在这个问题上撕裂我的头发,但它让我有点疯狂,可能是因为我已经到了一个点,我只是试图解决一个问题,我的尝试变得越来越清醒。

这是我的问题:

迭代一个整数并在其中找到其他整数的最佳方法是什么,然后如果它包含它那么抛出那个愚蠢的整数?

感谢您的帮助/阅读。

脚注: 这是我在这里提出的第一个问题,但我已经从这个网站的指导中受益了几个月了。抱歉,如果这个问题/解决方案是现存的,但我找了它,却无法找到一种方法来拼凑一个解决方案。大多数搜索结果都是“如何判断整数是否均匀”。

2 个答案:

答案 0 :(得分:2)

@root是正确的,你对如何优化它的假设是错误的,但我认为指出为什么你所做的不是在Python级别工作是有用的。

您的布尔问题

[num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable
首先评估

'024685' in str(num),因此它等同于for x in True - 这是不可能的。以上内容将写成:

[num for num in primes if not any(ch in '024685' for ch in str(num)]

str(num)获取每个字符并检查它是'024685'中的一个。

您的列表问题

这里有一条经验法则 - 不要修改你正在迭代的东西。如果您使用dict尝试此操作,则会引发异常 - 但对于list,它可能会出现默默错误,但偶尔会中断。

从列表中删除多个值时,最好构建一个仅保留所需值的新列表,例如:

no_zero = [num for num in primes if '0' not in str(num)]

如果你想修改原始素数:

primes[:] = no_zero

由于.remove(),您的上一个示例也失败了,将上述内容放在一起可以写成:

[num for num in primes if not any(num % i == 0 for i in (2, 5)]

<强>其它

您可能希望考虑将素数存储在set中 - 因为您不关心素数的顺序,并且会更快地进行成员资格测试。

答案 1 :(得分:0)

谢谢,Jon Clements。我今天能够通过以下脚本解决问题(请注意,我必须确保'024685'剥离器没有剥离出'2'和'5',因为这些是答案的一部分,这让我失去了一段时间...):

import math
import itertools

def prime_test(number):
  if all(number % x != 0 for x in range(2, int(math.sqrt(number)) + 1)):
    return True
  else:
return False

def find_primes(limit):
  primes = [2]
  for x in range(3, limit + 1, 2):
    if prime_test(x):
      primes.append(x)
    else:
      pass
  return primes

def circulate(number):
  circ_list = [number]
  x = 1
  while x < len(str(number)):
    number = str(number)[1:] + str(number)[0]
    circ_list.append(number)
    x += 1
  return circ_list

def main():
  primes = find_primes(1000000)
  no_evens = [x for x in primes if not any(ch in '024685' for ch in str(x) if len(str(x)) > 1)]

  circular_primes = [] 
  for prime in no_evens:
    if all(prime_test(x) for x in circulate(prime)):
      circular_primes.append(prime)
    else:
      pass

  return circular_primes, len(circular_primes)

if __name__ == '__main__':
  print(main())

我没有意识到的另一件事是我只是应该旋转数字,而不是提供它的所有可能的排列。当他们试图解决问题时,这些问题可能会让人失望。