Problem 38: Pandigital Multiples
View on Project EulerProject Euler Problem 38 Solution
EulerSolve provides an optimized solution for Project Euler Problem 38, Pandigital Multiples, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary For a positive integer \(b\), form the concatenated product $C(b,m)=\operatorname{concat}(b,2b,3b,\dots,mb), \qquad m \ge 2.$ We want \(C(b,m)\) to be a 9-digit number whose digits are exactly \(1,2,\dots,9\) in some order, and we must find the largest such value. The standard example is $C(192,3)=192384576,$ which is already 1-to-9 pandigital. The full problem is to determine which base \(b\) and which final multiplier \(m\) produce the maximum pandigital concatenation. Mathematical Approach The implementations solve the problem by turning it into a tiny exhaustive search, but that search is only convincing after we understand the exact digit-length and digit-usage constraints. The decisive length sum Let \(\ell(x)\) be the number of decimal digits of \(x\), and define $L_b(t)=\sum_{r=1}^{t}\ell(rb).$ A base \(b\) can be valid only if there is some \(m \ge 2\) with \(L_b(m)=9\). This quantity is the real state variable of the search: after appending the first \(t\) products, the current string has length \(L_b(t)\). Because every appended block contributes at least one digit, \(L_b(t)\) is strictly increasing in \(t\). So for any fixed base there is at most one relevant stopping point: the first \(t\) for which \(L_b(t)\ge 9\). If \(L_b(t)=9\), we have the only possible candidate for that base....
Detailed mathematical approach
Problem Summary
For a positive integer \(b\), form the concatenated product $C(b,m)=\operatorname{concat}(b,2b,3b,\dots,mb), \qquad m \ge 2.$ We want \(C(b,m)\) to be a 9-digit number whose digits are exactly \(1,2,\dots,9\) in some order, and we must find the largest such value.
The standard example is $C(192,3)=192384576,$ which is already 1-to-9 pandigital. The full problem is to determine which base \(b\) and which final multiplier \(m\) produce the maximum pandigital concatenation.
Mathematical Approach
The implementations solve the problem by turning it into a tiny exhaustive search, but that search is only convincing after we understand the exact digit-length and digit-usage constraints.
The decisive length sum
Let \(\ell(x)\) be the number of decimal digits of \(x\), and define $L_b(t)=\sum_{r=1}^{t}\ell(rb).$ A base \(b\) can be valid only if there is some \(m \ge 2\) with \(L_b(m)=9\). This quantity is the real state variable of the search: after appending the first \(t\) products, the current string has length \(L_b(t)\).
Because every appended block contributes at least one digit, \(L_b(t)\) is strictly increasing in \(t\). So for any fixed base there is at most one relevant stopping point: the first \(t\) for which \(L_b(t)\ge 9\). If \(L_b(t)=9\), we have the only possible candidate for that base. If \(L_b(t) \gt 9\), then no larger multiplier can ever repair the overshoot.
Why the base never needs five digits
Since \(m \ge 2\), any valid concatenation must include both \(b\) and \(2b\). Therefore $\ell(b)+\ell(2b)\le 9.$ If \(\ell(b)\ge 5\), then already \(\ell(b)+\ell(2b)\ge 10\), which is impossible. Hence every solution satisfies $1 \le b \le 9999.$ This is exactly why the C++, Python, and Java implementations enumerate bases only in that range.
There is also a useful structural consequence. A 4-digit base can only work with \(m=2\), because three 4-digit blocks would already contribute at least 12 digits. A 3-digit base can only survive a few multipliers, and a 1-digit base needs many of them. The code does not hard-code those cases; it lets the length sum \(L_b(t)\) discover them automatically.
Pandigitality is a digit-count invariant
For each decimal digit \(j\in\{0,1,\dots,9\}\), let \(c_j\) be the number of times \(j\) appears in \(C(b,m)\). The 1-to-9 pandigital condition is $c_0=0,\qquad c_j=1 \quad (1\le j\le 9).$ Because the candidate length is already fixed at 9, this condition becomes very cheap to verify: reject 0 immediately, reject any repeated nonzero digit immediately, and if no rejection occurs then the nine used digits must be exactly \(\{1,2,\dots,9\}\).
This is why the implementations only need a small boolean table indexed by digit. There is no deeper combinatorial machinery here; once the length is right, the entire problem reduces to a constant-size occupancy check.
Worked examples and the maximal candidate
The given example $C(192,3)=192384576$ has length \(3+3+3=9\) and uses each nonzero digit exactly once. A stronger benchmark comes from $C(9,5)=918273645,$ which starts with 9 and is also pandigital.
The winning case found by the exhaustive scan is $C(9327,2)=932718654,$ because \(9327\) contributes 4 digits, \(18654\) contributes 5 digits, and together they use the digits \(1\) through \(9\) exactly once. Since every admissible base \(1\le b\le 9999\) is checked and each base contributes at most one 9-digit candidate, this value is the true maximum.
How the Code Works
The C++, Python, and Java implementations all follow the same algorithm. They iterate through every base \(b\) from 1 to 9999, start with an empty decimal string, and append \(b,2b,3b,\dots\) one block at a time. The loop stops for that base as soon as the concatenation length reaches 9 or exceeds 9, which is exactly the monotonicity argument from \(L_b(t)\).
If the length lands on 9 and at least two products have been appended, the implementation performs the pandigital check with a 10-slot digit table. Encountering 0 or a repeated digit rejects the candidate immediately; otherwise the 9-digit value is compared with the current maximum. Because all valid candidates have the same length, a plain integer comparison is enough.
Each implementation also includes two tiny checkpoint tests before solving the full problem. One verifies that multiplying 192 by \(1,2,3\) produces the known concatenation \(192384576\), and the other verifies that the digit validator accepts \(123456789\). Those checkpoints guard both the concatenation logic and the pandigital test.
Complexity Analysis
The outer loop tries exactly 9999 bases. For any one base, the inner loop appends products only until the running length reaches 9, so it performs at most 9 iterations and usually far fewer. The pandigital test scans exactly 9 characters and uses a fixed-size digit table.
So the running time is effectively constant for this Project Euler instance, and if the upper base bound is written as \(B\) then the search is \(O(B)\) time with \(O(1)\) extra space. In practical terms the entire workload is only a few tens of thousands of primitive digit operations.
Footnotes and References
- Problem page: Project Euler Problem 38
- Pandigital numbers: Wikipedia - Pandigital number
- Positional notation: Wikipedia - Positional notation
- Concatenation: Wikipedia - Concatenation