Problem 3 — Largest Prime Factor

solved Fri, 3 Jul 2015, 15:27 · level 0 · difficulty 1% projecteuler.net github

The prime factors of $13195$ are $5, 7, 13$ and $29$.

What is the largest prime factor of the number $600851475143$?


Problem Analysis

The goal is to find the largest prime divisor of a target integer. The natural tool is trial division: I walk through candidate divisors in increasing order and remove each one that divides the number exactly. Two facts from elementary number theory turn this brute-force idea into an efficient one, and understanding why each holds is what lets me trust the result without any extra checks.

First, divisors come in pairs. If d divides n then so does n/d, and at least one member of each such pair is no larger than the square root of n. So if I scan candidates only up to the integer square root of the number and find no divisor, whatever remains cannot be composite — it must be prime itself. The search ceiling is therefore the square root of the value, not the value, which is the difference between an O(sqrt(n)) method and a hopeless O(n) one.

Second, whenever I find a factor I divide it out completely, leaving a remainder that is coprime to it. This shrinks the remainder and, with it, the square-root ceiling — which I then recompute against the smaller remainder. For an input that is a few small primes times one large one, that ceiling collapses almost immediately once the small factors are stripped away. The worst case remains O(sqrt(n)) — a genuinely prime input forces the loop all the way to its root — but typical inputs finish far sooner. There is a deeper payoff: because every smaller prime factor of a candidate is removed before the candidate is ever reached, any candidate that still divides the remainder must itself be prime. No explicit primality test is ever required.

Solution Approach

Trial Division with Aggressive Reduction (Python and C)

Both files share solution index 0 and implement the identical algorithm, so I describe them together and note the language differences at the end. The shape of the method is trial division with complete reduction after every hit.

Special-case the factor 2. I test 2 once, before the loop. If it divides the number I call reduce to strip out every copy of 2 and set largest_factor = 2; otherwise I set largest_factor = 1 as a harmless starting value. With the only even prime already handled, the main loop can step over odd candidates alone, halving its work.

The reduce helper. Given a number and a divisor known to divide it, reduce divides once and then keeps dividing while the divisor still goes in evenly, returning a value coprime to that divisor. This is the engine behind the no-primality-test guarantee: by fully eliminating each prime in order, I ensure a later composite candidate (say 9) cannot spuriously divide the remainder, because its prime constituent (3) was already removed.

Main loop over odd candidates. Starting at current_factor = 3 and stepping by 2, I loop while the remainder exceeds 1 and the candidate is at most search_limit — the integer square root of the current remainder. Each time a divisor is found, I reduce the remainder, record the divisor in largest_factor, and recompute search_limit from the now-smaller remainder. That recomputation is the dynamic ceiling that makes the method fast in practice.

Final answer. When the loop ends, a remainder still greater than 1 has survived every trial division up to its own square root and is therefore the largest prime factor, so I return it. Otherwise the last divisor removed during the loop is the answer.

The language differences are small. The C version uses long long to hold 64-bit values that would overflow a 32-bit int, computes the integer square root with sqrt() from <math.h> cast back to long long, and reads its input with atoll. The Python version uses the **0.5 idiom and int() to truncate. Both truncate toward zero, which is correct here because the loop comparison is <=, so flooring the limit never skips the boundary candidate.

workbench

Test cases

categoryinputanswer
dev number = 13195 29
dev number = 10 5
dev number = 20 5
main number = 600851475143 6857
extra number = 79376318561249 9999991

Results

solutioncategoryanswerverdict avg seconds cavg seconds py
p0003_s0 dev 29 correct 0.000001 (84) 0.000002 (84)
p0003_s0 dev 5 correct 0.000001 (84) 0.000002 (84)
p0003_s0 dev 5 correct 0.000001 (84) 0.000002 (84)
p0003_s0 main 6857 correct 0.000003 (84) 0.000033 (84)
p0003_s0 extra 9999991 correct 0.009184 (84) 0.177414 (84)

Files

Tags & blogs

Blogs