From 0abd5db93ccad2d54d9255ded7ac4aab99fd5811 Mon Sep 17 00:00:00 2001 From: Hyftar Date: Wed, 7 Oct 2020 21:38:40 -0400 Subject: [PATCH 1/2] Add project euler problem 51 --- project_euler/problem_51/__init__.py | 0 project_euler/problem_51/sol1.py | 106 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 project_euler/problem_51/__init__.py create mode 100644 project_euler/problem_51/sol1.py diff --git a/project_euler/problem_51/__init__.py b/project_euler/problem_51/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_51/sol1.py b/project_euler/problem_51/sol1.py new file mode 100644 index 000000000000..c630e51552ba --- /dev/null +++ b/project_euler/problem_51/sol1.py @@ -0,0 +1,106 @@ +from collections import Counter + +""" +https://projecteuler.net/problem=51 +Prime digit replacements +Problem 51 + +By replacing the 1st digit of the 2-digit number *3, it turns out that six of +the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime. + +By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit +number is the first example having seven primes among the ten generated numbers, +yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993. +Consequently 56003, being the first member of this family, is the smallest prime +with this property. + +Find the smallest prime which, by replacing part of the number (not necessarily +adjacent digits) with the same digit, is part of an eight prime value family. +""" + + +def sieve(n: int) -> list: + """ + Sieve of Erotosthenes + Function to return all the prime numbers up to a certain number + https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + + >>> sieve(3) + [2] + + >>> sieve(50) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] + """ + is_prime = [True] * n + is_prime[0] = False + is_prime[1] = False + is_prime[2] = True + + for i in range(3, int(n ** 0.5 + 1), 2): + index = i * 2 + while index < n: + is_prime[index] = False + index = index + i + + primes = [2] + + for i in range(3, n, 2): + if is_prime[i]: + primes.append(i) + + return primes + + +def digit_replacements(number: int) -> list: + """ + Returns all the possible families of digit replacements in a number which + contains at least one repeating digit + + >>> digit_replacements(544) + [[500, 511, 522, 533, 544, 555, 566, 577, 588, 599]] + + >>> digit_replacements(3112) + [[3002, 3112, 3222, 3332, 3442, 3552, 3662, 3772, 3882, 3992]] + """ + number = str(number) + replacements = [] + digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + + for duplicate in Counter(number) - Counter(set(number)): + family = [int(number.replace(duplicate, digit)) for digit in digits] + replacements.append(family) + + return replacements + + +def solution() -> int: + """ + Returns the solution of the problem + + >>> solution() + 121313 + """ + numbers_checked = set() + primes = set(sieve(1_000_000)) + + # Filter primes with less than 3 replaceable digits + primes = {x for x in primes if len(str(x)) - len(set(str(x))) >= 3} + + for prime in primes: + if prime in numbers_checked: + continue + + replacements = digit_replacements(prime) + + for family in replacements: + numbers_checked.update(family) + primes_in_family = primes.intersection(family) + + if len(primes_in_family) != 8: + continue + + return min(primes_in_family) + + +if __name__ == "__main__": + print(solution()) From a0bf56a66ce1137b1a543d70336c11a87a2c0154 Mon Sep 17 00:00:00 2001 From: Hyftar Date: Mon, 12 Oct 2020 12:52:00 -0400 Subject: [PATCH 2/2] Apply review suggestions --- project_euler/problem_51/sol1.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/project_euler/problem_51/sol1.py b/project_euler/problem_51/sol1.py index c630e51552ba..b160b5a2dbd4 100644 --- a/project_euler/problem_51/sol1.py +++ b/project_euler/problem_51/sol1.py @@ -1,5 +1,3 @@ -from collections import Counter - """ https://projecteuler.net/problem=51 Prime digit replacements @@ -18,17 +16,20 @@ adjacent digits) with the same digit, is part of an eight prime value family. """ +from collections import Counter +from typing import List -def sieve(n: int) -> list: + +def prime_sieve(n: int) -> List[int]: """ Sieve of Erotosthenes Function to return all the prime numbers up to a certain number https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - >>> sieve(3) + >>> prime_sieve(3) [2] - >>> sieve(50) + >>> prime_sieve(50) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] """ is_prime = [True] * n @@ -51,7 +52,7 @@ def sieve(n: int) -> list: return primes -def digit_replacements(number: int) -> list: +def digit_replacements(number: int) -> List[List[int]]: """ Returns all the possible families of digit replacements in a number which contains at least one repeating digit @@ -73,18 +74,22 @@ def digit_replacements(number: int) -> list: return replacements -def solution() -> int: +def solution(family_length: int = 8) -> int: """ Returns the solution of the problem - >>> solution() - 121313 + >>> solution(2) + 229399 + + >>> solution(3) + 221311 """ numbers_checked = set() - primes = set(sieve(1_000_000)) # Filter primes with less than 3 replaceable digits - primes = {x for x in primes if len(str(x)) - len(set(str(x))) >= 3} + primes = { + x for x in set(prime_sieve(1_000_000)) if len(str(x)) - len(set(str(x))) >= 3 + } for prime in primes: if prime in numbers_checked: @@ -96,7 +101,7 @@ def solution() -> int: numbers_checked.update(family) primes_in_family = primes.intersection(family) - if len(primes_in_family) != 8: + if len(primes_in_family) != family_length: continue return min(primes_in_family)