Project Euler, Problems 11 Through... Lots

Saturday, June 4, 2011
Tags: project euler, cplusplus, code sample

My last few posts were about the solutions I've been writing for the problems from Project Euler. There are a lot of problems, and commentary on the individual solutions aren't all that interesting.

Therefore, instead of posting solutions here I've started pushing them to a GitHub repository. At the time of writing, I've solved the first 45 problems.

A few of the problems offered opportunities to use dynamic programming, which is a technique I haven't encountered much since leaving college. I was glad to have a chance to use it again, and refresh my memory. The result tends to be a very fast solution.

Some problems require very large integers, and in some cases I'm using the long long type which isn't officially part of C++. However, even this isn't big enough for some problems. In a few cases I "faked" arbitrary precision integers, then at problem 20 I started to implement a separate BigInt class, but only having the parts I needed for that problem. I quickly decided that it would be more useful to use a common arbitrary precision library, and switched to using GMP for later problems that required very large integers. Reinventing the wheel isn't really the point of the problems, after all.

I eventually added a utility module for things that I've been using over and over again, such as a primality testing function. There are still many copies of this function in the earlier problems because I didn't bother to update them. Once I have the solution, I consider the program complete.

Project Euler, Problems 6 through 10

Wednesday, May 25, 2011
Tags: project euler, cplusplus, code sample

While I'm in the process of looking for a job, I've been working through some practice problems for Project Euler and posting my solutions.

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, except that it took me a little while to be convinced of the correctness of the optimization of adding 20 on each loop. Of course i mod 20 = 0 implies that 20 * n = i for some integer n.

#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;
}

Problem 6: Sum of Squares, Square of Sum

The sum of the squares of the first ten natural numbers is, 12 + 22 + ... + 102 = 385

The square of the sum of the first ten natural numbers is, (1 + 2 + ... + 10)2 = 552 = 3025

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

Another generally boring problem, but this one did offer one mildly interesting optimization. Calculating the sum of sequential natural numbers can be done with a formula rather than looping through them with an accumulator. There may be a formula for the sum of squares also, but I don't know if there is off the top of my head, so I did that portion with a loop.

#include <iostream>

long square_of_sum(long max)
{
    long sum = (max + 1) * max / 2;
    return sum * sum;
}

long sum_of_squares(long max)
{
    long sum = 0;

    for (long i=1; i<=max; i++) {
        sum += i * i;
    }

    return sum;
}


int main()
{
    std::cout << square_of_sum(100) - sum_of_squares(100) << std::endl;

    return 0;
}

Problem 7: 10001st Prime Number

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10001st prime number?

Re-using is_prime() from an earlier problem (and not for the last time), this is trivial. I constrain the loop to only odd numbers as a simple optimization.

#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()
{
    int count = 1;
    long long test;

    for (test=3; ; test+=2) {
        if (is_prime(test)) {
            if (++count == 10001) {
                break;
            }
        }
    }

    std::cout << test << std::endl;

    return 0;
}

Problem 8: Maximum Product of Consecutive Digits

Find the greatest product of five consecutive digits in the 1000-digit number.

I got this wrong the first time because I was thinking sum instead of product (which is perhaps a more interesting problem). Kind of ugly use of a global variable, but it gets the job done.

#include <iostream>

char digits[] =
"73167176531330624919225119674426574742355349194934"
"96983520312774506326239578318016984801869478851843"
"85861560789112949495459501737958331952853208805511"
"12540698747158523863050715693290963295227443043557"
"66896648950445244523161731856403098711121722383113"
"62229893423380308135336276614282806444486645238749"
"30358907296290491560440772390713810515859307960866"
"70172427121883998797908792274921901699720888093776"
"65727333001053367881220235421809751254540594752243"
"52584907711670556013604839586446706324415722155397"
"53697817977846174064955149290862569321978468622482"
"83972241375657056057490261407972968652414535100474"
"82166370484403199890008895243450658541227588666881"
"16427171479924442928230863465674813919123162824586"
"17866458359124566529476545682848912883142607690042"
"24219022671055626321111109370544217506941658960408"
"07198403850962455444362981230987879927244284909188"
"84580156166097919133875499200524063689912560717606"
"05886116467109405077541002256983155200055935729725"
"71636269561882670428252483600823257530420752963450";

long digit(int i)
{
    return digits[i] - '0';
}

int main()
{
    long largest = 0;

    for (int i=0; digits[i+4]; i++) {
        long product = digit(i) * digit(i+1) * digit(i+2) * digit(i+3) * digit(i+4);

        if (product > largest) {
            largest = product;
        }
    }

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

    return 0;
}

Problem 9: Pythagorean Triplet

A Pythagorean triplet is a set of three natural numbers, a < b < c, for which, a2 + b2 = c2

For example, 32 + 42 = 9 + 16 = 25 = 52.

There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc.

This one is slightly tricky if you want to avoid a lot of unnecessary tests, but overall there's not much to it.

#include <iostream>

int main()
{
    int a, b, c;

    for (a = 1; a < 998; a++) {
        for (b = a+1; ; b++) {
            c = 1000 - a - b;
            if (c < b || c < a) break;

            if (a*a + b*b == c*c) {
                std::cout << a << ' ' << b << ' ' << c << std::endl;
                std::cout << (a*b*c) << std::endl;
                return 0;
            }
        }
    }


    return 0;
}

Problem 10: Sum of Primes

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.

Using is_prime() again, there's not much to this other than the need to use long long again for the large sum.

#include <iostream>

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 sum = 2;
    long tally = 1;

    for (long i=3; i < 2000000; i+=2) {
        if (is_prime(i)) {
            sum += i;
            tally++;
        }
    }

    std::cout << sum << std::endl;
    std::cout << tally << " primes found" << std::endl;

    return 0;
}

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;
}