1 | """ |
||
0 ignored issues
–
show
|
|||
2 | Project Euler Problem 32: Pandigital Products |
||
3 | ============================================= |
||
4 | |||
5 | .. module:: solutions.problem32 |
||
6 | :synopsis: My solution to problem #32. |
||
7 | |||
8 | The source code for this problem can be |
||
9 | `found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem32.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` |
||
0 ignored issues
–
show
|
|||
15 | exactly once; for example, the :math:`5`-digit number, :math:`15234`, is :math:`1` through :math:`5` pandigital. |
||
0 ignored issues
–
show
|
|||
16 | |||
17 | The product :math:`7254` is unusual, as the identity, :math:`39 \\times 186 = 7254`, containing multiplicand, |
||
0 ignored issues
–
show
|
|||
18 | multiplier, and product is :math:`1` through :math:`9` pandigital. |
||
19 | |||
20 | Find the sum of all products whose multiplicand/multiplier/product identity can be written as a :math:`1` through |
||
0 ignored issues
–
show
|
|||
21 | :math:`9` pandigital. |
||
22 | |||
23 | .. note:: some products can be obtained in more than one way so be sure to only include it once in your sum. |
||
0 ignored issues
–
show
|
|||
24 | |||
25 | Solution Discussion |
||
26 | ################### |
||
27 | |||
28 | The single example given demonstrates that we need not consider prime factorisations but rather the product of two |
||
0 ignored issues
–
show
|
|||
29 | positive integers; :math:`a \\times b = c`. |
||
30 | |||
31 | The tuple :math:`(a,b,c)` is defined as :math:`d`-pandigital if the digits :math:`1` through :math:`d` appear precisely |
||
0 ignored issues
–
show
|
|||
32 | once in the digits comprising the three integers :math:`a,b,c` when represented in decimal. A pruned search will suffice |
||
0 ignored issues
–
show
|
|||
33 | to find all such :math:`d`-pandigital integers. |
||
34 | |||
35 | First, observe that :math:`c` is completely determined by :math:`a` and :math:`b`, we need only consider :math:`a` and |
||
0 ignored issues
–
show
|
|||
36 | :math:`b`. A naive search over all :math:`d`-digit integers :math:`a` and :math:`b` involves a search space of size |
||
0 ignored issues
–
show
|
|||
37 | :math:`10^{2 \\times d}`. However, this can be reduced by utilising some additional constraints imposed by the problem. |
||
0 ignored issues
–
show
|
|||
38 | |||
39 | Since we are searching for :math:`1` through :math:`9` pandigital numbers, we know there are no :math:`0` digits. Thus, |
||
0 ignored issues
–
show
|
|||
40 | :math:`a` and :math:`b` are positive integers without leading zeroes and the number of digits in their product is |
||
0 ignored issues
–
show
|
|||
41 | restricted according to: |
||
42 | |||
43 | .. math:: |
||
44 | |||
45 | &\\mbox{Let } c = a \\times b \\\\ |
||
46 | &\\mbox{Let } |x| \\mbox{ be the number of decimal digits in } x \\\\ |
||
47 | &|a| + |b| - 1 \\le |c| \le |a| + |b| |
||
48 | |||
49 | For :math:`(a,b,c)` to be :math:`d`-pandigital, the total number of digits in all integers must equal :math:`d`: |
||
0 ignored issues
–
show
|
|||
50 | |||
51 | .. math:: |
||
52 | |||
53 | |a| + |b| + |c| = d |
||
54 | |||
55 | Combining these two facts sets up useful constraints on :math:`b`, given :math:`a` and :math:`d`: |
||
56 | |||
57 | .. math:: |
||
58 | |||
59 | &|a| + |b| - 1 \\le |c| \\le |a| + |b| \\\\ |
||
60 | \\Rightarrow &|a| + |b| + |a| + |b| - 1 \\le |a| + |b| + |c| \\le |a| + |b| + |a| + |b| \\\\ |
||
61 | \\Rightarrow &2|a| + 2|b| - 1 \\le d \\le 2|a| + 2|b| \\\\ |
||
62 | \\Rightarrow &2|b| - 1 \\le d - 2|a| \\le 2|b| \\\\ |
||
63 | \\Rightarrow &d - 2|a| \\le 2|b| \\mbox{ and } 2|b| - 1 \\le d - 2|a| \\\\ |
||
64 | \\Rightarrow &\\frac{d}{2} - |a| \\le |b| \\mbox{ and } |b| \\le \\frac{d + 1}{2} - |a| \\\\ |
||
65 | \\Rightarrow &\\frac{d}{2} - |a| \\le |b| \\le \\frac{d + 1}{2} - |a| |
||
66 | |||
67 | Finally, the search over possible integers :math:`a` is bound by two overall constraints. Firstly, that :math:`(a,b,c)` |
||
0 ignored issues
–
show
|
|||
68 | must consist of exactly :math:`d` digits and that each integer must be at least one digit. Secondly, that the number of |
||
0 ignored issues
–
show
|
|||
69 | digits in :math:`c` will be at least equal to the number of digits in :math:`a`. |
||
70 | |||
71 | .. math:: |
||
72 | |||
73 | c = a \\times b \\Rightarrow |c| \\ge |a| \\mbox{ (for positive integers } a,b,c) |
||
74 | |||
75 | This leads to an upper-bound on the number of digits in :math:`a`: |
||
76 | |||
77 | .. math:: |
||
78 | |||
79 | &d = |a| + |b| + |c| \\ge |a| + |b| + |a| = 2|a| + |b| \\\\ |
||
80 | \\Rightarrow &d \\ge 2|a| + |b| \\\\ |
||
81 | &\\mbox{Since } |b| \\ge 1, 2|a| + |b| \\ge 2|a| + 1 \\\\ |
||
82 | \\Rightarrow &d \\ge 2|a| + 1 \\\\ |
||
83 | \\Rightarrow &\\frac{d - 1}{2} \\ge |a| \\\\ |
||
84 | \\Rightarrow &1 \\le |a| \\le \\frac{d - 1}{2} \\mbox{ (since all } a,b,c \\mbox{ must be at least one digit)} |
||
0 ignored issues
–
show
|
|||
85 | |||
86 | Solution Implementation |
||
87 | ####################### |
||
88 | |||
89 | .. literalinclude:: ../../solutions/problem32.py |
||
90 | :language: python |
||
91 | :lines: 94- |
||
92 | """ |
||
93 | |||
94 | from lib.digital import is_pandigital, num_digits |
||
95 | |||
96 | |||
97 | def solve(): |
||
98 | """ Compute the answer to Project Euler's problem #32 """ |
||
99 | |||
100 | # Problem specific parameters |
||
101 | base = 10 # use decimal representation |
||
102 | target = 9 # searching for target-pandigital numbers |
||
103 | a_max = base ** ((target - 1) // 2) # upper-bound on a |
||
104 | |||
105 | # Perform search over a and b looking for target-pandigital numbers |
||
106 | pandigitals = set() |
||
107 | for multiplicand in range(1, a_max): # search over values of a |
||
108 | a_len = num_digits(multiplicand) |
||
109 | b_lower_digits = (target + 1) // 2 - 1 # minimum number of digits in b |
||
110 | b_upper_digits = target // 2 + 1 # maximum number of digits in b |
||
111 | b_lower = base ** (b_lower_digits - a_len) # minimum value of b (half-open interval) |
||
112 | b_upper = base ** (b_upper_digits - a_len) # maximum value of b (half-open interval) |
||
113 | |||
114 | for multiplier in range(b_lower, b_upper): # search over values of b |
||
115 | product = multiplicand * multiplier # compute c = a * b |
||
116 | |||
117 | if is_pandigital([multiplicand, multiplier, product], target, 1, base): |
||
118 | pandigitals.add(product) # save any unique target-pandigital numbers 'product' |
||
119 | |||
120 | # Sum all unique target-pandigital integers |
||
121 | answer = sum(pandigitals) |
||
122 | return answer |
||
123 | |||
124 | |||
125 | expected_answer = 45228 |
||
0 ignored issues
–
show
The name
expected_answer does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$ ).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. ![]() |
|||
126 |
Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with
r
orR
are they interpreted as regular expressions.The escape sequence that was used indicates that you might have intended to write a regular expression.
Learn more about the available escape sequences. in the Python documentation.