Project Euler


Problem #1 - Multiples of 3 or 5

Original Problem Statement

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9.
The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.


Iterative Approach (Brute-Force)

At first glance, we could write some simple code to programmatically solve this by brute-force.
The strategy would be to iterate upwards from 1, and add the relevant numbers along the way.

The code for this would be as follows:
The computational complexity of this code would be:

  • Time → Linear, i.e. \(O(N)\)
  • Space → Constant, i.e. \(O(1)\)

Can we do better? → YES


Iterative Approach (Improved)

The previous approach ends up considering many irrelevant numbers.
We're only really concerned with multiples of 3 or 5.
Suppose we alter the code to ignore irrelevant numbers by skipping directly to our desired multiples.

The code would then be as follows:
However, note that we would end up counting certain values twice...

  • Multiples of 3 → 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, ...
  • Multiples of 5 → 5, 10, 15, 20, 25, 30, 35, ...
These are the multiples of 3 and 5, meaning the multiples of 15.

This can be resolved by simply subtracting the double-counted numbers.
We simply add this bit to our previous code:


The absolute runtime of the code has now been improved as we are ...
  • No longer iterating across every number less than \(N\)
  • No longer checking for divisibility by 3 or 5
However, even with these speed-ups, the time-complexity is still linear at \(O(N)\).

Can we do better !? → YES


Summation Approach

Let's instead directly examine the summation itself, \(S\), which we are looking to compute.

\(\hspace{1em}S = \displaystyle\sum_{x=1\text{ ; }3 \vert x \hspace{0.2em} \vee \hspace{0.2em} 5 \vert x}^{N-1} x\)

Inclusion-Exclusion Principle

Using the overall idea from the PIE (principle of inclusion-exclusion), we can break this down into separate, simpler summations.

\( \begin{align*} \hspace{1em}S &= \displaystyle\sum_{x=1\text{ ; }3 \vert x \hspace{0.2em} \vee \hspace{0.2em} 5 \vert x}^{N-1} x &\text{Original summation} \\ \hspace{1em} &= \displaystyle\sum_{x=1\text{ ; }3 \vert x}^{N-1} x + \displaystyle\sum_{x=1\text{ ; }5 \vert x}^{N-1} x - \displaystyle\sum_{x=1\text{ ; }3 \vert x \hspace{0.2em} \wedge \hspace{0.2em} 5 \vert x}^{N-1} x &\text{Separate using PIE} \\ \hspace{1em} &= \displaystyle\sum_{x=1\text{ ; }3 \vert x}^{N-1} x + \displaystyle\sum_{x=1\text{ ; }5 \vert x}^{N-1} x - \displaystyle\sum_{x=1\text{ ; }15 \vert x}^{N-1} x &\text{Multiples of 3 and 5 }\equiv\text{ Multiples of 15} \end{align*} \)

Notice here that the multiples of 15 are again subtracted, which avoids double-counting.

Gauss's Little Formula

Each of these summands is the sum of a finite arithmetic progression.
Thus we can take advantage of Gauss's Little Formula to convert each to a closed-form expression.
Recall the closed-form expression, as follows:

\( \hspace{1em}\displaystyle\sum_{i=1}^n i = \frac{n \cdot (n+1)}{2} \)

In the following, let \(N_m = \displaystyle\left\lfloor\frac{N-1}{m}\right\rfloor\), that is, the number of positive multiples of \(m\) below \(N\).

\( \begin{align*} \hspace{1em}S &= \displaystyle\sum_{x=1\text{ ; }3 \vert x}^{N-1} x + \displaystyle\sum_{x=1\text{ ; }5 \vert x}^{N-1} x - \displaystyle\sum_{x=1\text{ ; }15 \vert x}^{N-1} x &\text{Expression from above} \\ \hspace{1em} &= \displaystyle\sum_{i=1}^{\lfloor (N-1)/3 \rfloor} 3i + \sum_{i=1}^{\lfloor (N-1)/5 \rfloor} 5i - \sum_{i=1}^{\lfloor (N-1)/15 \rfloor} 15i &\text{Ignore non-multiples} \\ \hspace{1em} &= \displaystyle\sum_{i=1}^{N_3} 3i + \sum_{i=1}^{N_5} 5i - \sum_{i=1}^{N_{15}} 15i &\text{Substitute in }N_m \\ \hspace{1em} &= \displaystyle 3\cdot\sum_{i=1}^{N_3} i + 5\cdot\sum_{i=1}^{N_5} i - 15\cdot\sum_{i=1}^{N_{15}} i &\text{Factor out constants} \\ \hspace{1em} &= \displaystyle 3\cdot\frac{N_3(N_3+1)}{2} + 5\cdot\frac{N_5(N_5+1)}{2} - 15\cdot\frac{N_{15}(N_{15}+1)}{2} &\text{Apply Gauss's Little Formula} \end{align*} \)

Final Code

We've finally arrived at a closed-form expression to directly calculate the desired sum!
This can easily be coded as follows:
The time-complexity has been reduced to \(O(1)\) as we only need to compute a fixed number of arithmetic operations.


Answer

The answer can easily be computed manually with a calculator, giving the following:

\( \begin{align*} \hspace{1em}S &= \displaystyle 3\cdot\frac{N_3(N_3+1)}{2} + 5\cdot\frac{N_5(N_5+1)}{2} - 15\cdot\frac{N_{15}(N_{15}+1)}{2} \\ \hspace{1em} &= \displaystyle 3\cdot\frac{333(333+1)}{2} + 5\cdot\frac{199(199+1)}{2} - 15\cdot\frac{66(66+1)}{2} \\ \hspace{1em} &= 166,833 + 99,500 - 33,165 \\ \hspace{1em} &= 233,168 \end{align*} \)


My Solution on GitHub

The full Python3 code for my solution implementation can be found here: GitHub Solution