Project Euler, Problems 1 Through 5

Tuesday, May 24, 2011
Tags: project euler, cplusplus, code sample

Since I'm currently looking for a job I've started going through the exercises from Project Euler. The idea is to get some practice in the sort of programming problems that are given in interviews, refresh my C++ knowledge which has gotten rather rusty, and provide some code samples for potential employers.

Problem 1: Summing Multiples of 3 or 5

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.

This is a rather trivial problem, so I'll skip any discussion of it and just present my solution.

#include <iostream>

int main()
{
    int sum = 0;

    for (int i=3; i<1000; i++) {
        if (i % 3 == 0 || i % 5 == 0) {
            sum += i;
        }
    }

    std::cout << sum << std::endl;

    return 0;
}

Problem 2: Summing Even Fibonacci Numbers

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

Like the previous one, this is too trivial for any discussion.

#include <iostream>

int main()
{
    long sum = 0;
    long a = 1, b = 2;

    while (b < 4000000) {
        if (b % 2 == 0) {
            sum += b;
        }

        long temp = b + a;
        a = b;
        b = temp;
    }

    std::cout << sum << std::endl;

    return 0;
}

Problem 3: Largest Prime Factor

The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?

There are two moderately interesting things about this problem. The first is that it involves primality testing, which is slightly tricky. Naive solutions are quite easy, but more efficient solutions are much more tricky. I've stuck to the naive approach, since the numbers aren't sufficiently large to justify writing a complicated algorithm.

The second moderately interesting point is that this problem uses numbers outside the guaranteed range of a C++ long integer. Because of this, I used the long long type, which isn't standard in C++ yet (though it is widely supported).

#include <iostream>

// long long is not strict C++, unfortunately.

bool is_prime(long long val)
{
    if (val < 2) return false;
    if (val == 2) return true;
    if (val % 2 == 0) return false;

    long long i = 3;

    while (i * i <= val) {
        if (val % i == 0) {
            return false;
        }

        i += 2;
    }

    return true;
}

int main() {
    long long val = 600851475143LL;
    long long i = 2;
    long long largest = 0;

    while (i * i <= val) {
        if (is_prime(i) && val % i == 0) {
            largest = i;
        }

        i++;
    }

    std::cout << largest << std::endl;

    return 0;
}

Problem 4: Largest Palindromic Number

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.

Find the largest palindrome made from the product of two 3-digit numbers.

This was the first problem that I got wrong initially. The mistake I made was to iterate over the numbers from largest to smallest, and take the first palindrome product I found. This isn't actually the largest, however. It is simply the result that happens to have the largest value for one of the two factors. That is, the result I ended up with was 995 * 583 = 580085, while the actual answer is 993 * 913 = 906609. I think this is a somewhat understandable mistake, but certainly a type of error to watch out for.

#include <iostream>
#include <sstream>

bool is_palindrome(long val)
{
    std::ostringstream sout;
    sout << val;

    std::string text(sout.str());
    std::string reversed(text.rbegin(), text.rend());

    return text == reversed;
}

int main()
{
    long max = 0;

    for (int i=99; i<1000; i++) {
        for (int j=i; j<1000; j++) {
            int val = i*j;
            if (is_palindrome(val) && val > max) {
                max = val;
            }
        }
    }

    std::cout << max << std::endl;

    return 0;
}

Problem 5: Smallest Evenly Divisible Number

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

There's not much to say about this one. The simple optimization of adding 20 on each iteration didn't occur to me immediately, like it probably should have.

#include <iostream>

bool is_divisible(long val)
{
    for (int i=2; i<=20; i++) {
        if (val % i != 0) return false;
    }

    return true;
}

int main()
{
    for (long i=20; ; i+=20) {
        if (is_divisible(i)) {
            std::cout << i << std::endl;
            break;
        }
    }

    return 0;
}