Problem 47 — Distinct Primes Factors

solved Thu, 28 Nov 2019, 09:32 · level 1 · difficulty 4% projecteuler.net github

The first two consecutive numbers to have two distinct prime factors are:

$$\begin{align} 14 &= 2 \times 7\\ 15 &= 3 \times 5. \end{align}$$

The first three consecutive numbers to have three distinct prime factors are:

$$\begin{align} 644 &= 2^2 \times 7 \times 23\\ 645 &= 3 \times 5 \times 43\\ 646 &= 2 \times 17 \times 19. \end{align}$$

Find the first four consecutive integers to have four distinct prime factors each. What is the first of these numbers?


Problem Analysis

This problem rests on prime factorization - decomposing an integer into the primes whose product equals it. The decisive subtlety is the word distinct: we count only how many different primes divide a number, ignoring multiplicity. Thus 644 = 22 x 7 x 23 has three distinct prime factors (2, 7, 23) even though the prime 2 appears squared. The task is to find the first integer that begins a run of four consecutive integers, each having exactly four distinct prime factors.

The workhorse here is trial division: to factor n, I test candidate divisors d from 2 upward, and each time d divides n I record it and strip out every copy. The first efficiency observation is that I only need to test divisors up to the square root of n - if n had a factor larger than its square root, the cofactor would be smaller than the square root and would already have been found, so whatever survives the loop above 1 is itself a prime factor. The second, equally important observation is that no sieve or precomputed table is needed: the answer (134,043) is small, so a plain linear scan suffices. Counting distinct prime factors of n costs O(sqrt(n)), and scanning candidates up to the answer A while testing windows of length n gives an overall cost of about O(A * sqrt(A)) - a few million operations, which is trivial at this scale.

Solution Approach

Linear Scan with Trial Division (Python and C)

Both files implement the same algorithm, so I describe them together. There are two parts: a function that counts the distinct prime factors of one integer, and a search loop that finds the first window of n consecutive qualifying integers.

The counter uses trial division with in-place reduction. I begin at d = 2 and loop while d*d <= n. When d divides n, I increment the count once, then drain out every copy of that factor with an inner loop (while n % d == 0: n //= d). Draining all copies is precisely what makes a separate primality test unnecessary: by the time d reaches a composite value such as 4, the factor 2 has already been fully stripped, so 4 can never divide the reduced n. Every d that successfully divides is therefore guaranteed prime. After the loop, if n still exceeds 1, that remainder is a prime larger than the square root of the original, so I count it as well. The result is exactly the number of distinct prime factors.

The search loop starts at number = 2 and increments by 1. For each starting position it checks whether number, number+1, ..., number+(n-1) all have exactly n distinct prime factors, using early exit: the instant one element fails, the window is abandoned. In C this is a flag (all_match) plus a break; in Python it is not any(prime_factor_count(number + i) != n for i in range(0, n)), where any short-circuits identically.

Both programs take n as a command-line argument, so a single executable solves all three test cases (n=2, n=3, n=4) without modification. The Python version adds one layer of structure: prime_factorization returns a tuple of (prime, exponent) pairs and prime_factor_count simply returns its length. That is slightly more than this problem needs, but it leaves a reusable building block. The C version counts inline and omits the tuple machinery that C does not express naturally, which is marginally simpler and faster.

workbench

Test cases

categoryinputanswer
dev n = 2 14
dev n = 3 644
main n = 4 134043

Results

solutioncategoryanswerverdict avg seconds cavg seconds py
p0047_s0 dev 14 correct 0.000001 (63) 0.000009 (63)
p0047_s0 dev 644 correct 0.000017 (63) 0.000712 (63)
p0047_s0 main 134043 correct 0.022946 (63) 0.526794 (63)

Files

Tags & blogs

Blogs