|
1
|
|
|
""" |
|
2
|
|
|
Project Euler Problem 41: Pandigital Prime |
|
3
|
|
|
========================================== |
|
4
|
|
|
|
|
5
|
|
|
.. module:: solutions.problem41 |
|
6
|
|
|
:synopsis: My solution to problem #41. |
|
7
|
|
|
|
|
8
|
|
|
The source code for this problem can be |
|
9
|
|
|
`found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem41.py>`_. |
|
10
|
|
|
|
|
11
|
|
|
Problem Statement |
|
12
|
|
|
################# |
|
13
|
|
|
|
|
14
|
|
|
We shall say that an :math:`n`-digit number is pandigital if it makes use of all the digits :math:`1` to :math:`n` |
|
|
|
|
|
|
15
|
|
|
exactly once. For example, :math:`2143` is a :math:`4`-digit pandigital and is also prime. |
|
16
|
|
|
|
|
17
|
|
|
What is the largest :math:`n`-digit pandigital prime that exists? |
|
18
|
|
|
|
|
19
|
|
|
Solution Discussion |
|
20
|
|
|
################### |
|
21
|
|
|
|
|
22
|
|
|
First, observe that a decimal representation is assumed, so, only integers up to nine digits in length need be |
|
|
|
|
|
|
23
|
|
|
considered. However, the search space may be reduced even further by observing that some :math:`n`-digit pandigital |
|
|
|
|
|
|
24
|
|
|
patterns cannot possibly be prime. In particular, by enumeration of all pandigital numbers for a given :math:`n` or by |
|
|
|
|
|
|
25
|
|
|
the application of rules of divisibility. |
|
26
|
|
|
|
|
27
|
|
|
**Case: 1-digit pandigital (by enumeration)** |
|
28
|
|
|
|
|
29
|
|
|
:math:`1` is not prime |
|
30
|
|
|
:raw-html:`<br />` |
|
31
|
|
|
:math:`\\therefore` no :math:`1`-digit pandigital number is prime |
|
32
|
|
|
|
|
33
|
|
|
**Case: 2-digit pandigital (by enumeration)** |
|
34
|
|
|
|
|
35
|
|
|
:math:`12 = 2^2 \\times 3` is not prime |
|
36
|
|
|
:raw-html:`<br />` |
|
37
|
|
|
:math:`21 = 3 \\times 7` is not prime |
|
38
|
|
|
:raw-html:`<br />` |
|
39
|
|
|
:math:`\\therefore` no :math:`2`-digit pandigital number is prime |
|
40
|
|
|
|
|
41
|
|
|
**Case: 3-digit pandigital (by rules of divisibility)** |
|
42
|
|
|
|
|
43
|
|
|
Observe that any such number must contain the digits :math:`1,2,3` |
|
44
|
|
|
:raw-html:`<br />` |
|
45
|
|
|
Now, observe that :math:`1 + 2 + 3 = 6`, which is divisible by :math:`3` |
|
46
|
|
|
:raw-html:`<br />` |
|
47
|
|
|
:math:`\\Rightarrow` any :math:`3`-digit pandigital is divisible by :math:`3` |
|
48
|
|
|
:raw-html:`<br />` |
|
49
|
|
|
:math:`\\therefore` no :math:`3`-digit pandigital number is prime |
|
50
|
|
|
|
|
51
|
|
|
**Case: 5-digit pandigital (by rules of divisibility)** |
|
52
|
|
|
|
|
53
|
|
|
Observe that any such number must contain the digits :math:`1,2,3,4,5` |
|
54
|
|
|
:raw-html:`<br />` |
|
55
|
|
|
Now, observe that :math:`1 + 2 + 3 + 4 + 5 = 15` which is divisible by :math:`3` |
|
56
|
|
|
:raw-html:`<br />` |
|
57
|
|
|
:math:`\\Rightarrow` any :math:`5`-digit pandigital is divisible by :math:`3` |
|
58
|
|
|
:raw-html:`<br />` |
|
59
|
|
|
:math:`\\therefore` no :math:`5`-digit pandigital number is prime |
|
60
|
|
|
|
|
61
|
|
|
**Case: 6-digit pandigital (by rules of divisibility)** |
|
62
|
|
|
|
|
63
|
|
|
Observe that any such number must contain the digits :math:`1,2,3,4,5,6` |
|
64
|
|
|
:raw-html:`<br />` |
|
65
|
|
|
Now, observe that :math:`1 + 2 + 3 + 4 + 5 + 6 = 21` which is divisible by :math:`3` |
|
66
|
|
|
:raw-html:`<br />` |
|
67
|
|
|
:math:`\\Rightarrow` any :math:`6`-digit pandigital is divisible by :math:`3` |
|
68
|
|
|
:raw-html:`<br />` |
|
69
|
|
|
:math:`\\therefore` no :math:`6`-digit pandigital number is prime |
|
70
|
|
|
|
|
71
|
|
|
**Case: 8-digit pandigital (by rules of divisibility)** |
|
72
|
|
|
|
|
73
|
|
|
Observe that any such number must contain the digits :math:`1,2,3,4,5,6,7,8` |
|
74
|
|
|
:raw-html:`<br />` |
|
75
|
|
|
Now, observe that :math:`1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36` which is divisible by :math:`3` |
|
76
|
|
|
:raw-html:`<br />` |
|
77
|
|
|
:math:`\\Rightarrow` any :math:`8`-digit pandigital is divisible by :math:`3` |
|
78
|
|
|
:raw-html:`<br />` |
|
79
|
|
|
:math:`\\therefore` no :math:`8`-digit pandigital number is prime |
|
80
|
|
|
|
|
81
|
|
|
**Case: 9-digit pandigital (by rules of divisibility)** |
|
82
|
|
|
|
|
83
|
|
|
Observe that any such number must contain the digits :math:`1,2,3,4,5,6,7,8,9` |
|
84
|
|
|
:raw-html:`<br />` |
|
85
|
|
|
Now, observe that :math:`1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45` which is divisible by :math:`3` |
|
86
|
|
|
:raw-html:`<br />` |
|
87
|
|
|
:math:`\\Rightarrow` any :math:`9`-digit pandigital is divisible by :math:`3` |
|
88
|
|
|
:raw-html:`<br />` |
|
89
|
|
|
:math:`\\therefore` no :math:`9`-digit pandigital number is prime |
|
90
|
|
|
|
|
91
|
|
|
So, we only need to consider :math:`4`-digit and :math:`7`-digit numbers. |
|
92
|
|
|
|
|
93
|
|
|
Originally, my solution enumerated primes up to (and including) :math:`7`-digits and then checked whether each prime is |
|
|
|
|
|
|
94
|
|
|
:math:`n`-digit pandigital. While this algorithm produces the correct answer, we can do better. The runtime of this |
|
|
|
|
|
|
95
|
|
|
algorithm is dominated by the cost of prime sieving. |
|
96
|
|
|
|
|
97
|
|
|
My second, superior, solution enumerates :math:`n`-digit pandigital numbers and checks whether they are prime. This |
|
|
|
|
|
|
98
|
|
|
solution is faster because there are generally less pandigital numbers than primes for the same number of digits (at |
|
|
|
|
|
|
99
|
|
|
least for the search interval considered): |
|
100
|
|
|
|
|
101
|
|
|
- The number of :math:`7`-digit primes is about :math:`\\frac{10^7}{\\log(10^7)} \\approx 620420` |
|
102
|
|
|
- The number of :math:`7`-digit pandigital numbers is precisely :math:`7! = 5040` |
|
103
|
|
|
|
|
104
|
|
|
Solution Implementation |
|
105
|
|
|
####################### |
|
106
|
|
|
|
|
107
|
|
|
.. literalinclude:: ../../solutions/problem41.py |
|
108
|
|
|
:language: python |
|
109
|
|
|
:lines: 112- |
|
110
|
|
|
""" |
|
111
|
|
|
|
|
112
|
|
|
from itertools import chain |
|
113
|
|
|
|
|
114
|
|
|
from lib.numbertheory import is_probably_prime |
|
115
|
|
|
from lib.sequence import Pandigitals |
|
116
|
|
|
|
|
117
|
|
|
|
|
118
|
|
|
def solve(): |
|
119
|
|
|
""" Compute the answer to Project Euler's problem #41 """ |
|
120
|
|
|
answer = 0 |
|
121
|
|
|
for candidate in chain(Pandigitals(n=4), Pandigitals(n=7)): |
|
122
|
|
|
if is_probably_prime(candidate): |
|
123
|
|
|
answer = max(answer, candidate) # the n-digit pandigital is also prime |
|
124
|
|
|
return answer |
|
125
|
|
|
|
|
126
|
|
|
|
|
127
|
|
|
expected_answer = 7652413 |
|
|
|
|
|
|
128
|
|
|
|
This check looks for lines that are too long. You can specify the maximum line length.