HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Project Euler #1 efficiency

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
projectefficiencyeuler

Problem

I've started solving Project Euler problems. Is the code completely optimized?

Question:


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 N.

My solution:

import java.util.LinkedList;
import java.util.Scanner;

public class Solution {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int testCases = sc.nextInt();
        for (int i = 0; i  al = new LinkedList<>();
        int sums = 0;
        for (int i = 1; i < input; i++) {
            if (isMulThree(i) || isMulFive(i)) {
                al.add(i);

            }
        }
        for (int count : al) {
            sums = sums + count;
        }
        return sums;
    }
}

Solution

I had a general review primed up for this question, but other answers beat me to those more general aspects.

@TheKittyKat provided a good starting point on the most efficient means of calculating the sum of each sequence, and then subtracting the double-count

Now, the solution @TheKittyKat provides for each sequence, is, for example:

for (int i = 5; i < n; i += 5) {
    sum += i;
}


If we were to put this in a function:

public static int sumOfSequence(int value, int limit) {
    int sum = 0;
    for (int i = value; value < limit; i += value) {
        sum += i;
    }
    return sum;
}


So, having generalized that, we can do:

int total = sumOfSequence(3, N) + sumOfSequence(5, N) - sumOfSequence(15, N);


But, there's a trick, the function:

public static int sumOfSequence(int value, int limit) {
    int sum = 0;
    for (int i = value; value < limit; i += value) {
        sum += i;
    }
    return sum;
}


can be reduced to a single \$O(1)\$ operation using the math behind a Arithmetic Progression / sum-of-sequence

This boils down to the fact that the sum of a sequence:

$$
1k + 2k + ... + (n-1)k + nk = \tfrac{n(1k + nk)}{2}.
$$

The equation:

$$
\tfrac{n(1k + nk)}{2}
$$

can be rewritten as:

$$
\tfrac{kn(1 + n)}{2}
$$

Now, either \$n\$ or \$(1 + n)\$ is even, and any even number times any other even number, is even, so you can always safely halve it.

Thus, the function can be reduced to:

public static int sumOfSequence(int value, int limit) {
    final int count = (limit - 1) / value;
    return value * count * ( count + 1) / 2;
}


So, the end result, is:

public static int sumOfSequence(int value, int limit) {
    final int count = (limit - 1) / value;
    return value * count * ( count + 1) / 2;
}

public static void main(String[] args) {

    int limit = 1000;

    int sum = -sumOfSequence(15, limit) + sumOfSequence(3, limit) + sumOfSequence(5, limit);
    System.out.println(sum);
}

Code Snippets

for (int i = 5; i < n; i += 5) {
    sum += i;
}
public static int sumOfSequence(int value, int limit) {
    int sum = 0;
    for (int i = value; value < limit; i += value) {
        sum += i;
    }
    return sum;
}
int total = sumOfSequence(3, N) + sumOfSequence(5, N) - sumOfSequence(15, N);
public static int sumOfSequence(int value, int limit) {
    int sum = 0;
    for (int i = value; value < limit; i += value) {
        sum += i;
    }
    return sum;
}
public static int sumOfSequence(int value, int limit) {
    final int count = (limit - 1) / value;
    return value * count * ( count + 1) / 2;
}

Context

StackExchange Code Review Q#67103, answer score: 13

Revisions (0)

No revisions yet.