【问题标题】:Largest Prime Factor Python最大素数 Python
【发布时间】:2014-03-08 05:24:10
【问题描述】:

我正在尝试使用 Python 找到给定数字 (600851475143) 的最大素数。我编写了以下代码,但问题是,它需要很长时间,可能是因为它正在迭代列表数百万次。如何优化这个过程?

def factors(n):
    list = []
    i = 1
    while i < n:
        if n % i == 0:
            list.append(i)
        i += 1
    return list

def prime(n):
    list = factors(n)
    primelist = []
    for item in list[1:]:
        if item % 2 != 0 and item % 3 != 0 and item % 4 != 0 and item  \
        % 5 != 0 and item % 6 != 0 and item % 7 != 0 and item % 8 != 0 \
        and item % 9 != 0:
            primelist.append(item)
    return primelist

def greatestprime(n):
    list = prime(n)
    list[0] = lnum
    i = 1
    while i < len(list):
        if list[i] > lnum:
            lnum = list[i]
    return lnum

#print(greatestprime(600851475143))

【问题讨论】:

标签: list python-3.x primes prime-factoring


【解决方案1】:

如果您只分解单个数字n,那么测试从 2 到 sqrt(n)n 的平方根)的每个数字的天真方法应该可以快速得到最大为 10 的数字的结果14 。您编写的代码超出了必要范围。

稍微好一点的方法是:

  • 测试 2,然后测试每个奇数
  • 测试 2、3、5,然后测试 6k + 1 和 6k + 5 形式的所有整数,其中 k >= 1
  • 上面的两种方法是wheel factorization,n = 2 和 n = 2*3 = 6。您可以将其提高到 n = 2*3*5*7 = 210(更高不会带来太多效率)。

稍微好一点的方法是通过Eratosthenes 筛子生成素数并进行测试(无冗余测试)。还有更好的方法,例如 Pollard's rho 因式分解,但除非您处理更多数字,否则这两种方法都过大了。

【讨论】:

  • OP 没有测试每一个数字; OP 只测试数字 2-9。此外,OP 不是在寻找质数检查,而是寻找质因数分解,这是真正需要“更多代码”的其他东西。
  • @poke:素数分解和素数检查几乎相同(对于小型实例)。但是 OP 真的是写太多代码了。
【解决方案2】:

找到一个数的最大质因数并没有人们想象的那么难。

from itertools import takewhile
from math import floor, sqrt

def _prime_numbers_helper():
    yield 2
    yield 3
    i = 1
    while True:
        yield 6 * i - 1
        yield 6 * i + 1
        i += 1

def prime_numbers(ceiling=None):
    if ceiling is None:
        yield from _prime_numbers_helper()
    else:
        yield from takewhile(lambda number: number <= ceiling, _prime_numbers_helper())

def largest_prime_factor(number):
    if number % int(number) != 0:
        raise ValueError('The number must be an integer.')
    if number in (0, 1):
        raise ValueError('There is no largest prime factor of {}.'.format(number))

    while True:
        for i in prime_numbers(floor(sqrt(abs(number)))):
            if number % i == 0:
                number //= i
                break
        else:
            return number

else 语句仅在 for 语句执行完成时执行(即当数字无法进一步分解时)。

for 语句应该改用真正的素数生成器,但我懒得写一个有效的实现。

请注意,这假设您使用的是 Python 3.3 或更高版本。

出于好奇,这是针对 Project Euler Problem 3 的吗?

【讨论】:

  • 另一件事是,在找到每个因素后重新开始搜索。考虑分解 125:test 2, test 3, test 5, divide 5, result 25, test 2, test 3, test 5, divide 5, result 5, test 2, done。 2 和 3 的所有重复测试都是多余的。你真的可以从同一个因子 5 继续搜索。当这个实现时,不需要昂贵的素数生成来测试,因为这样找到的所有因子无论如何都保证是素数。使用你的helper 很好,它可以廉价地减少候选人的数量(顺便说一句,这就是主轮分解)。 :)
  • 重新开始搜索背后的想法是,找出主要因素比继续搜索直到找到最大的主要因素要快。显然,如果数字本身是素数,这没有区别。我想我可以从迄今为止发现的最大素因子开始搜索,因为那时不会有小于它的素因子,但我懒得修复它。哈哈。我同意prime_numbers 具有误导性。这个想法是您将用真正的素数生成器替换实现。我忘记了我的理论,但1 被认为是素数吗?
  • 不,1 不被视为素数。从头开始显然总是比继续慢,您执行额外的测试需要时间。从顶部搜索是不好的,因为更多的数字具有更小的因素。当只分解一个数字时,不需要真正的素数生成器。
  • 我收回这句话:“不需要真正的素数生成器,在这里只分解一个数字时。”
【解决方案3】:

n的因子很容易通过试除法找到,只要n不太大即可; :: 运算符在 fs 链表的前面插入 f

function factors(n)
    f, fs := 2, []
    while f * f <= n
        while n % f == 0
            n := n / f
            fs := f :: fs
        f := f + 1
    if n <> 1
        n :: fs
    return reverse(fs)

如果您对使用素数编程感兴趣,或者如果您正在寻找一个库来帮助解决涉及素数的 Project Euler 问题,我在我的博客中谦虚地推荐 this essay,其中包括东西,把上面的伪代码翻译成 Python:

def td_factors(n, limit=1000000):
    if type(n) != int and type(n) != long:
        raise TypeError('must be integer')
    fs = []
    while n % 2 == 0:
        fs += [2]
        n /= 2
    if n == 1:
        return fs
    f = 3
    while f * f <= n:
        if limit < f:
            raise OverflowError('limit exceeded')
        if n % f == 0:
            fs += [f]
            n /= f
        else:
            f += 2
    return fs + [n]

【讨论】:

    【解决方案4】:

    试试:

    number = whatever your number is
    divisor = 2
    
    while divisor < number:
        if number % divisor == 0:
            number /= divisor
        else:
            divisor += 1
    

    你一直在划分数字,直到它不再可能 - 这是他们在小学教你解决这类问题的方法(尽管他们永远不会要求你对 12 位数字做这个技巧)。当你得到一个数字时

    一开始看起来很奇怪,但它确实有效:每次通过都会减小您正在查看的数字的大小并划分较小的素数。例如,如果该数字可以被 32 整除,那么您只需将 2 除以 6 次,然后再继续,这样做您将缩小 可能number 因子的数字池.如果您的数字已经是它自己最大的主要因素,您仍然需要迭代它以验证这一点。在正常情况下(number 是其最大素数和某个合数的乘积),您甚至会在检查最大素数是否除以它之前,先除掉它的所有较小因数。

    另一个有用的启发式方法是找到数字的平方根,并且只检查小于该平方根的数字:n &gt; sqrt(number) 不可能是 n 的(整数)因子 number。不过,我喜欢第一种方法。

    sike,没有看到有人已经发布了一个非常相似的解决方案。

    【讨论】:

    • 看起来很慢(可能是因为python的工作方式)但是算法很好!
    【解决方案5】:

    这里有两种可能性。一位来自this blog

    def gpf(n):
        """
        Find the greatest prime factor of n
        """
        if n < 2:
            raise ValueError('{} does not have a prime factorization'.format(n))
        divisor = 2
        while n > 1:
            if not n % divisor:
                n /= divisor
                divisor -= 1
            divisor += 1
        return divisor
    

    你的例子:

    In [15]: gpf(600851475143)
    Out[15]: 6857
    
    In [16]: timeit gpf(600851475143)
    1000 loops, best of 3: 1.55 ms per loop
    

    或使用SymPy库:

    from sympy import factorint
    def gpf(n):
        return max(factorint(n).keys())
    

    (请注意,这已经定义了 n

    【讨论】:

      【解决方案6】:

      这就是我的做法:

      def is_prime(m):
          """Checks if the argument is a prime number."""
      
          if m < 2: return False
      
          for i in xrange(2, m):
              if m % i == 0:
                  return False
      
          return True
      
      def get_largest_prime_factor(k):
          """Gets the largest prime factor for the argument."""
      
          prime_divide = (p for p in xrange(1, k))
          for d in prime_divide:
      
              if k % d == 0 and is_prime(k / d):
                  return k / d
      
      print get_largest_prime_factor(600851475143)
      

      【讨论】:

        【解决方案7】:
        n=int(input(""))
        
        prime_factors=[]
        for i in range(2,int(n**0.5+1)):
          if n%i==0:
            for x in range(2,int(i**0.5+1)): 
              if i%x==0:
                break
            else:
              prime_factors.append(i)
              
        print("prime factors are:",prime_factors)
        print("largest prime factor is",prime_factors[-1])
        

        输入:600851475143
        输出:主要因素是:[71, 839, 1471, 6857]
        最大的质因数是 6857

        【讨论】:

          【解决方案8】:

          实际最终程序:使用长除法旧方法查找因子 并仅存储最大/当前因子,直到找到最后一个。

          我知道这是一个老问题,但想分享我解决问题的方法。

          def prime_factors_old_fashioned_factorization(number):
              y=1
              for x in range(2,number):
                  if(number%x==0):
                      print("number=",number,"\t and X=",x)
                      while(number%x==0):
                          print("number=",number)
                          number=number/x
                      print("new number=",number)
                      y=x
                      x=x+1
                      if((number==1) or (number<x)):
                          break;
              print("largest prime factor=",y)
          

          【讨论】:

          • 你的答案比已经在这里的答案更好还是更差,比如e.g. this one
          • 对我来说更快。如果有帮助的话。
          • 确实如此。将输出 1 作为标志,表示输入的数字是素数。例如: >>prime_factors_old_fashioned_factorization(31) >>Largest prime factor=1 这告诉我们输入的数字 (31) 是一个素数。
          【解决方案9】:
          # Largest prime factor of a number
          def prime_fact(n):
              p=[]
              f=[]
              p.append(1)
              for d in range(2,n+1):
                  if n%d==0:
                      f.append(d)
          
              for v in f:
                  if (v==1 or v==2):
                      p.append(v)
                  else:
                      for i in range(2,v):
                          if v%i ==0:
                              break
          
                      else:
                          p.append(v)
              print(f'Factors of the number are {f}')
              print(f'Primefactors are {p}')
              print(f'Largest prime factor is {p[-1]}')
          

          【讨论】:

            猜你喜欢
            • 2015-06-28
            • 1970-01-01
            • 2014-11-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-16
            相关资源
            最近更新 更多