Skip to content

Commit 50d7ed8

Browse files
authored
Add project euler problem 51 (TheAlgorithms#3018)
* Add project euler problem 51 * Apply review suggestions
1 parent 695217e commit 50d7ed8

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

project_euler/problem_51/__init__.py

Whitespace-only changes.

project_euler/problem_51/sol1.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""
2+
https://projecteuler.net/problem=51
3+
Prime digit replacements
4+
Problem 51
5+
6+
By replacing the 1st digit of the 2-digit number *3, it turns out that six of
7+
the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.
8+
9+
By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit
10+
number is the first example having seven primes among the ten generated numbers,
11+
yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993.
12+
Consequently 56003, being the first member of this family, is the smallest prime
13+
with this property.
14+
15+
Find the smallest prime which, by replacing part of the number (not necessarily
16+
adjacent digits) with the same digit, is part of an eight prime value family.
17+
"""
18+
19+
from collections import Counter
20+
from typing import List
21+
22+
23+
def prime_sieve(n: int) -> List[int]:
24+
"""
25+
Sieve of Erotosthenes
26+
Function to return all the prime numbers up to a certain number
27+
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
28+
29+
>>> prime_sieve(3)
30+
[2]
31+
32+
>>> prime_sieve(50)
33+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
34+
"""
35+
is_prime = [True] * n
36+
is_prime[0] = False
37+
is_prime[1] = False
38+
is_prime[2] = True
39+
40+
for i in range(3, int(n ** 0.5 + 1), 2):
41+
index = i * 2
42+
while index < n:
43+
is_prime[index] = False
44+
index = index + i
45+
46+
primes = [2]
47+
48+
for i in range(3, n, 2):
49+
if is_prime[i]:
50+
primes.append(i)
51+
52+
return primes
53+
54+
55+
def digit_replacements(number: int) -> List[List[int]]:
56+
"""
57+
Returns all the possible families of digit replacements in a number which
58+
contains at least one repeating digit
59+
60+
>>> digit_replacements(544)
61+
[[500, 511, 522, 533, 544, 555, 566, 577, 588, 599]]
62+
63+
>>> digit_replacements(3112)
64+
[[3002, 3112, 3222, 3332, 3442, 3552, 3662, 3772, 3882, 3992]]
65+
"""
66+
number = str(number)
67+
replacements = []
68+
digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
69+
70+
for duplicate in Counter(number) - Counter(set(number)):
71+
family = [int(number.replace(duplicate, digit)) for digit in digits]
72+
replacements.append(family)
73+
74+
return replacements
75+
76+
77+
def solution(family_length: int = 8) -> int:
78+
"""
79+
Returns the solution of the problem
80+
81+
>>> solution(2)
82+
229399
83+
84+
>>> solution(3)
85+
221311
86+
"""
87+
numbers_checked = set()
88+
89+
# Filter primes with less than 3 replaceable digits
90+
primes = {
91+
x for x in set(prime_sieve(1_000_000)) if len(str(x)) - len(set(str(x))) >= 3
92+
}
93+
94+
for prime in primes:
95+
if prime in numbers_checked:
96+
continue
97+
98+
replacements = digit_replacements(prime)
99+
100+
for family in replacements:
101+
numbers_checked.update(family)
102+
primes_in_family = primes.intersection(family)
103+
104+
if len(primes_in_family) != family_length:
105+
continue
106+
107+
return min(primes_in_family)
108+
109+
110+
if __name__ == "__main__":
111+
print(solution())

0 commit comments

Comments
 (0)