diff --git a/README.rst b/README.rst index ad5ae092..ea22274d 100644 --- a/README.rst +++ b/README.rst @@ -107,7 +107,7 @@ Olivia's Project Euler Solutions | | | | |Lu-Cov| |br| | | | | | |LuaCheck| | +------------+----------------------------+--------+-------------------+ - | Python | CPython 3.6+ |br| | 81 | |Python| |br| | + | Python | CPython 3.6+ |br| | 82 | |Python| |br| | | | Pypy 3.6+ |br| | | |Py-Cov| |br| | | | GraalPy 23.1+ |br| | | |CodeQL| |br| | | | Browser [#]_ | | |PythonLint| | diff --git a/_data/answers.tsv b/_data/answers.tsv index 4a5fc800..9e6043f8 100644 --- a/_data/answers.tsv +++ b/_data/answers.tsv @@ -49,6 +49,7 @@ ID type size answer 48 int 64 9110846700 49 int 64 296962999629 50 int 32 997651 +51 int 32 121313 52 int 32 142857 53 int 16 4075 55 uint 8 249 diff --git a/docs/index.rst b/docs/index.rst index a98332ba..a602b026 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -178,6 +178,8 @@ Problems Solved +-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`050`| | | | | | | |:py-d:`0050`| | +-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+ + |:prob:`051`| | | | | | | |:py-d:`0051`| | + +-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`052`| | | | | | | |:py-d:`0052`| | +-----------+-----------+------------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`053`| | | | | | | |:py-d:`0053`|:rs-d:`0053`| diff --git a/docs/src/python/p0051.rst b/docs/src/python/p0051.rst new file mode 100644 index 00000000..b1e33149 --- /dev/null +++ b/docs/src/python/p0051.rst @@ -0,0 +1,25 @@ +Python Implementation of Problem 51 +=================================== + +View source code :source:`python/src/p0051.py` + +Includes +-------- + +- :py:func:`~python.src.lib.primes.is_prime` +- :external:py:func:`itertools.combinations` +- :external:py:func:`itertools.count` +- :external:py:func:`itertools.product` + +Problem Solution +---------------- + +.. automodule:: python.src.p0051 + :members: + :undoc-members: + +.. literalinclude:: ../../../python/src/p0051.py + :language: python + :linenos: + +.. tags:: prime-number, digit-manipulation diff --git a/python/README.rst b/python/README.rst index f24e52c4..c6882ccc 100644 --- a/python/README.rst +++ b/python/README.rst @@ -177,6 +177,7 @@ Problems Solved - ☒ `48 <./src/p0048.py>`__ - ☒ `49 <./src/p0049.py>`__ - ☒ `50 <./src/p0050.py>`__ +- ☒ `51 <./src/p0051.py>`__ - ☒ `52 <./src/p0052.py>`__ - ☒ `53 <./src/p0053.py>`__ - ☒ `55 <./src/p0055.py>`__ diff --git a/python/src/p0051.py b/python/src/p0051.py new file mode 100644 index 00000000..d8a98270 --- /dev/null +++ b/python/src/p0051.py @@ -0,0 +1,64 @@ +""" +Project Euler Problem 51 + +Again, surprised how effective the brute force solution was + +Problem: + +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. +""" +from itertools import combinations, count, product +from typing import List, Tuple + +from .lib.primes import is_prime + +all_digits = tuple(str(x) for x in range(10)) +non_zero = all_digits[1:] +endings = ("1", "3", "7", "9") + + +def main() -> int: + for L in count(5): + largest_possible: int = 10**L + for Ls in range(1, L - 1): + for indices in combinations(range(L - 1), Ls): + mask = ["d"] * L # d can be replaced by any digit + for index in indices: + mask[index] = "s" # s can be replaced by any single digit + valid, smallest = check_mask(mask, largest_possible, L, Ls) + if valid: + return smallest + return -1 # pragma: no cover + + +def check_mask(mask: List[str], largest_possible: int, L: int, Ls: int) -> Tuple[bool, int]: + for start, middle, end in product(non_zero, product(all_digits, repeat=(L - Ls - 2)), endings): + digits = (start, *middle, end) + current = mask.copy() + for digit in digits: + current[current.index("d")] = digit + valid = 0 + smallest = largest_possible + if current[0] == "s": + selection = non_zero + else: + selection = all_digits + for s in selection: + new = [x if x != "s" else s for x in current] + num = int("".join(new)) + if is_prime(num): + valid += 1 + smallest = min(smallest, num) + elif 10 - int(s) + valid <= 8: + break + else: + return True, smallest + return False, 0 diff --git a/python/test_euler.py b/python/test_euler.py index 0aa434a6..b3bc05b5 100644 --- a/python/test_euler.py +++ b/python/test_euler.py @@ -19,9 +19,7 @@ answers: Dict[int, Union[int, str]] = { x: get_answer(x) for x in ( - *range(1, 51), - 52, - 53, + *range(1, 54), *range(55, 61), 63, 67,