Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 8: Largest Product in a Series

View on Project Euler

Project Euler Problem 8 Solution

EulerSolve provides an optimized solution for Project Euler Problem 8, Largest Product in a Series, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary The input is the fixed 1000-digit decimal string from the problem statement. For a chosen window length \(w\), the task is to find the largest product of \(w\) consecutive digits. In the original Euler instance, \(w = 13\). Mathematically, we are evaluating a function \(M(w)\) on one fixed digit sequence. The implementations also define sensible boundary behavior: if \(w \le 0\) or \(w\) is longer than the string itself, the returned value is \(0\). Mathematical Approach Let the digits be \(d_0, d_1, \dots, d_{m-1}\), where each \(d_i \in \{0,1,\dots,9\}\) and \(m=1000\) for the Euler input. Window Products Form the Entire Search Space For every valid starting position \(i\), define the window product $P_i=\prod_{t=0}^{w-1} d_{i+t}, \qquad 0 \le i \le m-w.$ The desired value is therefore $M(w)=\max_{0 \le i \le m-w} P_i.$ This formula already explains why a complete scan is correct: every block of \(w\) consecutive digits appears exactly once as one of these windows, so taking the maximum over all valid starts cannot miss the optimum. Zeros Split the Search into Independent Runs Because all digits are nonnegative, a zero destroys the whole product of any window that touches it....

Detailed mathematical approach

Problem Summary

The input is the fixed 1000-digit decimal string from the problem statement. For a chosen window length \(w\), the task is to find the largest product of \(w\) consecutive digits. In the original Euler instance, \(w = 13\).

Mathematically, we are evaluating a function \(M(w)\) on one fixed digit sequence. The implementations also define sensible boundary behavior: if \(w \le 0\) or \(w\) is longer than the string itself, the returned value is \(0\).

Mathematical Approach

Let the digits be \(d_0, d_1, \dots, d_{m-1}\), where each \(d_i \in \{0,1,\dots,9\}\) and \(m=1000\) for the Euler input.

Window Products Form the Entire Search Space

For every valid starting position \(i\), define the window product

$P_i=\prod_{t=0}^{w-1} d_{i+t}, \qquad 0 \le i \le m-w.$

The desired value is therefore

$M(w)=\max_{0 \le i \le m-w} P_i.$

This formula already explains why a complete scan is correct: every block of \(w\) consecutive digits appears exactly once as one of these windows, so taking the maximum over all valid starts cannot miss the optimum.

Zeros Split the Search into Independent Runs

Because all digits are nonnegative, a zero destroys the whole product of any window that touches it. If the string is decomposed into maximal zero-free runs \(R_1,\dots,R_s\), and a typical run is written as \(R_j=(e_0,e_1,\dots,e_{r_j-1})\), then every window either lies completely inside one run or has product \(0\).

That lets us rewrite the problem as

$M(w)=\max\left(0,\max_j M_j(w)\right), \qquad M_j(w)=\max_{0 \le i \le r_j-w}\prod_{t=0}^{w-1} e_{i+t},$

where a run contributes only when \(r_j \ge w\). This is the key structural fact of Problem 8: zeros do not merely lower a candidate product, they partition the whole search into independent nonzero segments plus the fallback value \(0\).

Consecutive Windows on a Zero-Free Run

Inside a run with no zeros, consecutive window products satisfy an exact recurrence. If

$P_i=\prod_{t=0}^{w-1} e_{i+t},$

then for \(0 \le i < r_j-w\),

$P_{i+1}=P_i \cdot \frac{e_{i+w}}{e_i}.$

This identity is valid precisely because \(e_i \neq 0\). It is the natural mathematical basis for a rolling-product or sliding-window optimization. The provided implementations do not use this recurrence; they recompute each \(P_i\) from scratch. That choice keeps the code simple and avoids special zero bookkeeping, which is perfectly reasonable for a 1000-digit input.

Worked Examples from the Verified Checks

For the short sequence \(123456789\) with \(w=2\), the window products are

$2, 6, 12, 20, 30, 42, 56, 72,$

so the maximum is \(72\), attained by the final window \(89\).

For the 1000-digit Euler string with \(w=4\), one verified optimal block is \(9989\), giving

$9 \times 9 \times 8 \times 9 = 5832.$

For the original target \(w=13\), the maximizing block is \(5576689664895\), and its product is

$5 \times 5 \times 7 \times 6 \times 6 \times 8 \times 9 \times 6 \times 6 \times 4 \times 8 \times 9 \times 5 = 23514624000.$

Why Direct Multiplication Is Enough Here

The largest possible product of 13 decimal digits is \(9^{13}=2541865828329\), well below the range of signed 64-bit integers. So there is no overflow problem for the Euler parameter.

There are exactly \(1000-13+1=988\) candidate windows, and the straightforward method performs \(13\) digit multiplications per window. That is only

$988 \times 13 = 12844$

digit multiplications, plus trivial loop overhead. For such a small fixed workload, the simpler \(O(mw)\) scan is mathematically transparent and practically fast.

How the Code Works

Input Representation and Boundary Cases

The C++, Python, and Java implementations store the 1000-digit number as one immutable string literal. They all accept a window length parameter, and they all return \(0\) immediately when the requested window is nonpositive or longer than the digit string.

Exhaustive Window Scan

The implementation then loops over every legal starting position \(i\). For each start, it initializes a product accumulator to \(1\), multiplies the \(w\) digits in positions \(i,i+1,\dots,i+w-1\), and compares that product with the best value seen so far.

In other words, the outer loop enumerates the windows from the formula for \(M(w)\), and the inner loop reconstructs the invariant “the accumulator equals the product of the current window” from scratch each time.

Cross-Language Consistency

All three versions implement the same mathematics. The C++ and Java versions use 64-bit integer arithmetic; Python integers are arbitrary precision, so the same computation is still exact. The code also includes the same two checkpoints in every language: the toy case \((123456789, 2) \mapsto 72\), and the 1000-digit check with \(w=4\) giving \(5832\).

Complexity Analysis

For a digit string of length \(m\), there are \(m-w+1\) windows, and each one is recomputed using \(w\) multiplications. The running time is therefore

$O((m-w+1)w)=O(mw).$

The memory usage is \(O(1)\) beyond the stored digit string and a few scalar variables.

For the Euler input with \(m=1000\) and \(w=13\), this means 988 window evaluations and 12,844 digit multiplications. A rolling-product implementation on zero-free runs could reduce the time to \(O(m)\), but the current exhaustive scan is already more than sufficient.

Footnotes and References

  1. Problem page: Project Euler - Problem 8
  2. Product in mathematics: Wikipedia - Product (mathematics)
  3. Zero and its algebraic role: Wikipedia - Zero (mathematics)
  4. Sliding-window technique: GeeksforGeeks - Window Sliding Technique
  5. Asymptotic complexity notation: Wikipedia - Big O notation

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 7 · All Project Euler solutions · Next: Problem 9

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮