简体   繁体   English

计算素因数的算法建议(Python初学者)

[英]Algorithm recommendation for calculating prime factors (Python Beginner)

SPOILER ALERT! 警惕! THIS MAY INFLUENCE YOUR ANSWER TO PROJECT EULER #3 这可能会影响您对第3个用户的回答

I managed to get a working piece of code but it takes forever to compute the solution because of the large number I am analyzing. 我设法获得了一段有效的代码,但是由于要分析的代码太多,因此需要花费很多时间来计算解决方案。

I guess brute force is not the right way... 我想蛮力不是正确的方法...

Any help in making this code more efficient? 对提高此代码的效率有帮助吗?

# What is the largest prime factor of the number 600851475143

# Set variables
number = 600851475143
primeList = []
primeFactorList = []

# Make list of prime numbers < 'number'
for x in range(2, number+1):
    isPrime = True
    # Don't calculate for more than the sqrt of number for efficiency
    for y in range(2, int(x**0.5)+1):
        if x % y == 0:
            isPrime = False
            break
    if isPrime:
        primeList.append(x)

# Iterate over primeList to check for prime factors of 'number'
for i in primeList:
    if number % i == 0:
        primeFactorList.append(i)

# Print largest prime factor of 'number'
print(max(primeFactorList))

You can use user defined function such as 您可以使用用户定义的功能,例如

def isprime(n):
if n < 2:
    return False
for i in range(2,(n**0.5)+1):
    if n % i == 0:
        return False

return True

it will return boolean values. 它将返回布尔值。 You can use this function for verifying prime factors. 您可以使用此功能来验证主要因素。

OR 要么

you can continuously divide the number by 2 first 您可以先将数字连续除以2

n = 600851475143
while n % 2 == 0:
    print(2),
    n = n / 2

n has to be odd now skip 2 in for loop, then print every divisor n必须为奇数,现在在for循环中跳过2,然后打印每个除数

for i in range(3,n**0.5+1,2):
    while n % i== 0:
        print(i)
        n = n / i

at this point, n will be equal to 1 UNLESS n is a prime. 此时,n将等于1,除非n是质数。 So 所以

if n > 1:
    print(n)

to print itself as the prime factor. 打印自己作为首要因素。

Have fun exploring 玩得开心探索

I'll first just address some basic problems in the particular algorithm you attempted: 首先,我将解决您尝试的特定算法中的一些基本问题:

You don't need to pre-generate the primes. 您不需要预先生成素数。 Generate them on the fly as you need them - and you'll also see that you were generating way more primes than you need (you only need to try the primes up to sqrt(600851475143) ) 在需要时即时生成它们-您还将看到生成的质数比所需的更多(您只需要尝试高达sqrt(600851475143)

# What is the largest prime factor of the number 600851475143

# Set variables
number = 600851475143
primeList = []
primeFactorList = []

def primeList():
    # Make list of prime numbers < 'number'
    for x in range(2, number+1):
        isPrime = True
        # Don't calculate for more than the sqrt of number for efficiency
        for y in range(2, int(x**0.5)+1):
            if x % y == 0:
                isPrime = False
                break
        if isPrime:
            yield x

# Iterate over primeList to check for prime factors of 'number'
for i in primeList():
    if i > number**0.5:
        break
    if number % i == 0:
        primeFactorList.append(i)

# Print largest prime factor of 'number'
print(max(primeFactorList))

By using a generator (see the yield ?) PrimeList() could even just return prime numbers forever by changing it to: 通过使用生成器(请参见yield吗?), PrimeList()甚至可以通过将其更改为以下内容来永远返回质数:

def primeList():
    x = 2
    while True:
        isPrime = True
        # Don't calculate for more than the sqrt of number for efficiency
        for y in range(2, int(x**0.5)+1):
            if x % y == 0:
                isPrime = False
                break
        if isPrime:
            yield x
        x += 1

Although I can't help but optimize it slightly to skip over even numbers greater than 2: 尽管我忍不住对其进行了稍微优化,以跳过大于2的偶数:

def primeList():
    yield 2
    x = 3
    while True:
        isPrime = True
        # Don't calculate for more than the sqrt of number for efficiency
        for y in range(2, int(x**0.5)+1):
            if x % y == 0:
                isPrime = False
                break
        if isPrime:
            yield x
        x += 2

If you abandon your initial idea of enumerating the primes and trying them one at a time against number , there is an alternative: Instead deal directly with number and factor it out -- ie, doing what botengboteng suggests and breaking down the number directly. 如果您放弃最初列举质数并一次对number进行质number 测试的初衷 ,则有另一种选择:直接处理number并将其分解出来-即,执行botengboteng建议并直接分解数字。

This will be much faster because we're now checking far fewer numbers: 这将更快,因为我们现在要检查的数字要少得多:

number = 600851475143                                                           

def factors(num):                                                               
    factors = []                                                                
    if num % 2 == 0:                                                            
        factors.append(2)                                                       
    while num % 2 == 0:                                                         
        num = num // 2                                                          
    for f in range(3, int(num**0.5)+1, 2):                                      
        if num % f == 0:                                                        
            factors.append(f)                                                   
        while num % f == 0:                                                     
            num = num // f
         # Don't keep going if we're dividing by potential factors               
         # bigger than what is left.                                             
         if f > num:
            break                                                      
    if num > 1:                                                                 
        factors.append(num)                                                     
    return factors                                                              

# grab last factor for maximum.                                                                                
print(factors(number)[-1])

First calculate the sqrt of your number as you've done. 首先,计算完您的数字的平方根。

number = 600851475143
number_sqrt = (number**0.5)+1

Then in your outermost loop only search for the prime numbers with a value less than the sqrt root of your number. 然后,在最外层循环中,仅搜索值小于数字平方根的质数。 You will not need any prime number greater than that. 您将不需要大于此的质数。 (You can infer any greater based on your list). (您可以根据列表推断出更大的值)。

for x in range(2, number_sqrt+1):

To infer the greatest factor just divide your number by the items in the factor list including any combinations between them and determine if the resultant is or is not a prime. 要推断最大因子,只需将您的数字除以因子列表中的项目(包括它们之间的任何组合),然后确定结果是否为质数。

No need to recalculate your list of prime numbers. 无需重新计算素数列表。 But do define a function for determining if a number is prime or not. 但是一定要定义一个函数来确定数字是否为质数。

I hope I was clear. 我希望我很清楚。 Good Luck. 祝好运。 Very interesting question. 非常有趣的问题。

I made this code, everything is explained if you have questions feel free to comment it 我编写了这段代码,如果您有任何疑问,请解释所有内容

def max_prime_divisor_of(n):
    for p in range(2, n+1)[::-1]: #We try to find the max prime who divides it, so start descending
        if n%p is not 0: #If it doesn't divide it does not matter if its prime, so skip it
            continue
        for i in range(3, int(p**0.5)+1, 2): #Iterate over odd numbers
            if p%i is 0:
                break #If is not prime, skip it
            if p%2 is 0: #If its multiple of 2, skip it
                break
        else: #If it didn't break it, is prime and divide our number, we got it
            return p #return it
        continue #If it broke, means is not prime, instead is just a non-prime divisor, skip it

If you don't know: What it does in range(2, n+1)[::-1] is the same as reversed(range(2, n+1)) so it means that instead of starting with 2 , it starts with n because we are searching the max prime. 如果您不知道:range(2, n+1)[::-1]它的作用与reversed(range(2, n+1))因此它表示不是从2开始,它以n开头,因为我们正在搜索最大素数。 (Basically it reverses the list to start that way) (基本上,它会反转列表以这种方式开始)


Edit 1: This code runs faster the more divisor it has, otherwise is incredibly slow, for general purposes use the code above 编辑1:除数越多,此代码运行得越快,否则,它的运行速度会非常慢,对于一般用途,请使用上面的代码

def max_prime_divisor_of(n): #Decompose by its divisor
    while True:
        try:
            n = next(n//p for p in range(2, n) if n%p is 0) #Decompose with the first divisor that we find and repeat
        except StopIteration: #If the number doesn't have a divisor different from itself and 1, means its prime
            return n

If you don't know: What it does in next(n//p for p in range(2, n) if n%p is 0) is that gets the first number who is divisor of n 如果您不知道: next(n//p for p in range(2, n) if n%p is 0)是获得第一个除以n的数的数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM