From ef0d09218a61ba6c034484012dd3430100e38901 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Fri, 9 Oct 2020 13:44:44 +0200 Subject: [PATCH 1/5] Added solution for Project Euler problem 38. Fixes: #2695 --- project_euler/problem_38/__init__.py | 0 project_euler/problem_38/sol1.py | 74 ++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 project_euler/problem_38/__init__.py create mode 100644 project_euler/problem_38/sol1.py diff --git a/project_euler/problem_38/__init__.py b/project_euler/problem_38/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_38/sol1.py b/project_euler/problem_38/sol1.py new file mode 100644 index 000000000000..254274079b24 --- /dev/null +++ b/project_euler/problem_38/sol1.py @@ -0,0 +1,74 @@ +""" +Take the number 192 and multiply it by each of 1, 2, and 3: + +192 × 1 = 192 +192 × 2 = 384 +192 × 3 = 576 + +By concatenating each product we get the 1 to 9 pandigital, 192384576. We will call +192384576 the concatenated product of 192 and (1,2,3) + +The same can be achieved by starting with 9 and multiplying by 1, 2, 3, 4, and 5, +giving the pandigital, 918273645, which is the concatenated product of 9 and +(1,2,3,4,5). + +What is the largest 1 to 9 pandigital 9-digit number that can be formed as the +concatenated product of an integer with (1,2, ... , n) where n > 1? +""" + + +def is_9_palindromic(n: int) -> bool: + """ + Checks whether n is a 9-digit 1 to 9 pandigital number. + >>> is_9_palindromic(12345) + False + >>> is_9_palindromic(156284973) + True + >>> is_9_palindromic(1562849733) + False + """ + s = str(n) + return len(s) == 9 and set(s) == set("123456789") + + +def solution() -> int: + """ + Return the largest 1 to 9 pandigital 9-digital number that can be formed as the + concatenated product of an integer with (1,2,...,n) where n > 1. + + Solution: + Since n>1, the largest candidate for the solution will be a concactenation of + a 4-digit number and its double, a 5-digit number. + Let a be the 4-digit number. + a has 4 digits => 1000 <= a < 10000 + 2a has 5 digits => 10000 <= 2a < 100000 + => 5000 <= a < 10000 + + The concatenation of a with 2a = a * 10^5 + 2a + so our candidate for a given a is 100002 * a. + We iterate through the search space 5000 <= a < 10000 in reverse order, + calculating the candidates for each a and checking if they are 1-9 pandigital. + + In case there are no 4-digit numbers that satisfy this property, we check + the 3-digit numbers with a similar formula (the example a=192 gives a lower + bound on the length of a): + a has 3 digits, etc... + => 100 <= a < 334, candidate = a * 10^6 + 2a * 10^3 + 3a + = 1002003 * a + + """ + for base_num in range(9999, 4999, -1): + candidate = 100002 * base_num + if is_9_palindromic(candidate): + return candidate + + for base_num in range(333, 99, -1): + candidate = 1002003 * base_num + if is_9_palindromic(candidate): + return candidate + + return 192384576 + + +if __name__ == "__main__": + print(solution()) From b50f045edc1de05349d8bc7b3b9f8df1d5706e21 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Thu, 15 Oct 2020 10:20:45 +0200 Subject: [PATCH 2/5] Update docstring and 0-padding in directory name. Reference: #3256 --- project_euler/{problem_38 => problem_038}/__init__.py | 0 project_euler/{problem_38 => problem_038}/sol1.py | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) rename project_euler/{problem_38 => problem_038}/__init__.py (100%) rename project_euler/{problem_38 => problem_038}/sol1.py (95%) diff --git a/project_euler/problem_38/__init__.py b/project_euler/problem_038/__init__.py similarity index 100% rename from project_euler/problem_38/__init__.py rename to project_euler/problem_038/__init__.py diff --git a/project_euler/problem_38/sol1.py b/project_euler/problem_038/sol1.py similarity index 95% rename from project_euler/problem_38/sol1.py rename to project_euler/problem_038/sol1.py index 254274079b24..2d4090a34ec4 100644 --- a/project_euler/problem_38/sol1.py +++ b/project_euler/problem_038/sol1.py @@ -1,4 +1,6 @@ """ +Project Euler Problem 38: https://projecteuler.net/problem=38 + Take the number 192 and multiply it by each of 1, 2, and 3: 192 × 1 = 192 @@ -67,8 +69,9 @@ def solution() -> int: if is_9_palindromic(candidate): return candidate + # just in case return 192384576 if __name__ == "__main__": - print(solution()) + print(f"{solution() = }") From bea153c452cfae83bb330ca5dad7eb04fd74a65f Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Thu, 15 Oct 2020 12:26:31 +0200 Subject: [PATCH 3/5] Renamed is_9_palindromic to is_9_pandigital. --- project_euler/problem_038/sol1.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/project_euler/problem_038/sol1.py b/project_euler/problem_038/sol1.py index 2d4090a34ec4..1b39a3ecd8a2 100644 --- a/project_euler/problem_038/sol1.py +++ b/project_euler/problem_038/sol1.py @@ -19,14 +19,14 @@ """ -def is_9_palindromic(n: int) -> bool: +def is_9_pandigital(n: int) -> bool: """ Checks whether n is a 9-digit 1 to 9 pandigital number. - >>> is_9_palindromic(12345) + >>> is_9_pandigital(12345) False - >>> is_9_palindromic(156284973) + >>> is_9_pandigital(156284973) True - >>> is_9_palindromic(1562849733) + >>> is_9_pandigital(1562849733) False """ s = str(n) @@ -61,12 +61,12 @@ def solution() -> int: """ for base_num in range(9999, 4999, -1): candidate = 100002 * base_num - if is_9_palindromic(candidate): + if is_9_pandigital(candidate): return candidate for base_num in range(333, 99, -1): candidate = 1002003 * base_num - if is_9_palindromic(candidate): + if is_9_pandigital(candidate): return candidate # just in case From 44c3decfa54da99f61078cb532869f9803dcf7b3 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Thu, 15 Oct 2020 12:54:02 +0200 Subject: [PATCH 4/5] Changed just-in-case return value for solution() to None. --- project_euler/problem_038/sol1.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/project_euler/problem_038/sol1.py b/project_euler/problem_038/sol1.py index 1b39a3ecd8a2..bb88dd42c6ce 100644 --- a/project_euler/problem_038/sol1.py +++ b/project_euler/problem_038/sol1.py @@ -18,6 +18,10 @@ concatenated product of an integer with (1,2, ... , n) where n > 1? """ +from __future__ import annotations + +from typing import Union + def is_9_pandigital(n: int) -> bool: """ @@ -33,7 +37,7 @@ def is_9_pandigital(n: int) -> bool: return len(s) == 9 and set(s) == set("123456789") -def solution() -> int: +def solution() -> Union[int, None]: """ Return the largest 1 to 9 pandigital 9-digital number that can be formed as the concatenated product of an integer with (1,2,...,n) where n > 1. @@ -69,8 +73,7 @@ def solution() -> int: if is_9_pandigital(candidate): return candidate - # just in case - return 192384576 + return None if __name__ == "__main__": From 9671f23b4fca04d867978d55490e80a359659ccd Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Fri, 16 Oct 2020 11:55:31 +0200 Subject: [PATCH 5/5] Moved exmplanation to module-level docstring and deleted unnecessary import --- project_euler/problem_038/sol1.py | 43 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/project_euler/problem_038/sol1.py b/project_euler/problem_038/sol1.py index bb88dd42c6ce..6d54f6df7ff8 100644 --- a/project_euler/problem_038/sol1.py +++ b/project_euler/problem_038/sol1.py @@ -16,9 +16,27 @@ What is the largest 1 to 9 pandigital 9-digit number that can be formed as the concatenated product of an integer with (1,2, ... , n) where n > 1? -""" -from __future__ import annotations +Solution: +Since n>1, the largest candidate for the solution will be a concactenation of +a 4-digit number and its double, a 5-digit number. +Let a be the 4-digit number. +a has 4 digits => 1000 <= a < 10000 +2a has 5 digits => 10000 <= 2a < 100000 +=> 5000 <= a < 10000 + +The concatenation of a with 2a = a * 10^5 + 2a +so our candidate for a given a is 100002 * a. +We iterate through the search space 5000 <= a < 10000 in reverse order, +calculating the candidates for each a and checking if they are 1-9 pandigital. + +In case there are no 4-digit numbers that satisfy this property, we check +the 3-digit numbers with a similar formula (the example a=192 gives a lower +bound on the length of a): +a has 3 digits, etc... +=> 100 <= a < 334, candidate = a * 10^6 + 2a * 10^3 + 3a + = 1002003 * a +""" from typing import Union @@ -41,27 +59,6 @@ def solution() -> Union[int, None]: """ Return the largest 1 to 9 pandigital 9-digital number that can be formed as the concatenated product of an integer with (1,2,...,n) where n > 1. - - Solution: - Since n>1, the largest candidate for the solution will be a concactenation of - a 4-digit number and its double, a 5-digit number. - Let a be the 4-digit number. - a has 4 digits => 1000 <= a < 10000 - 2a has 5 digits => 10000 <= 2a < 100000 - => 5000 <= a < 10000 - - The concatenation of a with 2a = a * 10^5 + 2a - so our candidate for a given a is 100002 * a. - We iterate through the search space 5000 <= a < 10000 in reverse order, - calculating the candidates for each a and checking if they are 1-9 pandigital. - - In case there are no 4-digit numbers that satisfy this property, we check - the 3-digit numbers with a similar formula (the example a=192 gives a lower - bound on the length of a): - a has 3 digits, etc... - => 100 <= a < 334, candidate = a * 10^6 + 2a * 10^3 + 3a - = 1002003 * a - """ for base_num in range(9999, 4999, -1): candidate = 100002 * base_num