0

I'm trying to solve a problem from the Project Euler archive: https://projecteuler.net/problem=3

The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ?

I tried solving for 13195 first. My original idea was to create a list with all the prime numbers lower than the given number. I used the Sieve of Erathostenes algorithm to do this. Then, using a for loop I iterated through all those prime numbers adding the ones that are factors of the given number to a separate list. I sorted the list and printed the largest factor. When I ran the script I got one extra number in the factors list that was not a factor of the given number.

for num = 13915 the output should have been [13, 29, 5, 7] but instead I got [13, 29, 377, 5, 7]

I wasn't able to figure out where 377 came from. I'm aware my solution is not the most efficient one but I tried solving this problem myself. So my questions are:

Where did 377 come from? Can you suggest a more efficient way to solve this problem?

I apologize for any inconveniences as I'm new to problem solving in Python.

primes = []
num = 13195
factors = []
for i in range(1, num + 1):
    #sieve of erathostenes
    if i % 2 != 0 and i % 3 != 0 and i % 5 != 0 and i % 7 != 0 and i != 1:
        primes.append(i)

if num >= 10:
    primes.append(2)
    primes.append(3)
    primes.append(5)
    primes.append(7)

sorted(primes)

for i in range(len(primes)):
    prime = primes[i]
    if num % prime == 0:
        factors.append(primes[i])


print(factors)
factors.sort()
print(factors[len(factors) - 1])
Bonko
  • 1
  • 3
    `sorted(primes)` doesn't do anything, because you don't assign the result to anything. – Mark Ransom Mar 17 '21 at 16:09
  • 3
    Finding *all* primes below a number in order to factor it seems like overkill. Also, `i % 2 != 0 and i % 3 != 0 and i % 5 != 0 and i % 7 != 0` isn't a way to test if something is a prime. Note that `377 = 13*29`, but your code classifies it as a prime. – John Coleman Mar 17 '21 at 16:09
  • 2
    For more efficient ways to generate primes, we have two questions with really excellent answers: https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n and https://stackoverflow.com/questions/2211990/how-to-implement-an-efficient-infinite-generator-of-prime-numbers-in-python – Thierry Lathuille Mar 17 '21 at 16:10

2 Answers2

1

You don't need to generate primes. A direct factorisation of the number will be more efficient:

def primeFactors(N):  # generator for all prime factors
    p = 2
    while p*p<=N:       # only need up to √N (remaining N)
        while N%p == 0: # p is a factor (will be a prime)
            yield p     # return primes as many times as they appear
            N //= p     # remove the prime factor from the number
        p += 1 + p%2    # next potential prime
    if N>1: yield N     # beyond √N whatever remains is a prime factor

output: (take the maximum factor found)

print(max(primeFactors(600851475143))) # 6857
Alain T.
  • 24,524
  • 2
  • 27
  • 43
  • You don't even need to take the max, since you're generating them in order. The max should be the last one. – Mark Ransom Mar 19 '21 at 04:36
  • And I'm not sure the `while` loop is the best choice here, I might have used `for p in itertools.chain([2], range(3, math.ceil(math.sqrt(N)), 2))` – Mark Ransom Mar 19 '21 at 04:44
  • I agree that the function could be specialized to only return the last (maximum) factor. The while loop however is useful because N decreases during the process (as we find factors) and this greatly reduces the number of iterations. A for loop would not allow for that unless we put in a break conditions, which would turn it into like a bastardized while loop. – Alain T. Mar 19 '21 at 12:32
  • Also, that chain trick would need to use chain.from_iterables otherwise it would create an internal list with all potential factors before proceeding . I've tried that in the past and there are faster solutions to step by two past prime 2. The insignificant speed differences made me keep the simplest form in the end. – Alain T. Mar 19 '21 at 12:36
  • I missed the fact that N was decreasing, forget I said anything. – Mark Ransom Mar 19 '21 at 12:39
0

use this to get the factors of a number sorted from largest to smallest

number = 13915
list_of_factors=sorted([int(number/n) for n in range(2,number//2 +1) if number % n ==0 ],reverse=True) 

result is [2783, 1265, 605, 253, 121, 115, 55, 23, 11, 5]

Gerry P
  • 4,258
  • 2
  • 5
  • 15
  • For `600851475143` your comprehension would iterate over 300 billion possible `n`. To say that this isn't an efficient way to get `6857 (the largest prime factor)` is an understatement. Furthermore, you would still need to filter the returned list to discover which of the factors were prime. – John Coleman Mar 17 '21 at 19:23