euler !! 5


Let's do two easy problems and then a harder one.

Problem 9:
A Pythagorean triplet is a set of three natural numbers, a < b < c, for which a^2 + b^2 = c^2. There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc.

We can accomplish this by using a simple list comprehension to enumerate all the Pythagorean triplets that fit these constraints:

[ [a,b,c] | a <- [1..999], b <- [1..a], let c = 1000 - a - b, a^2 + b^2 == c^2]

Since we know that a + b + c = 1000, we can define c in terms of a and b. We can also avoid doing excessive computation by taking b from the range [1..a] instead of [1..999]. Once we have our set of three numbers, it's a simple matter of multiplying them together to get the final answer:

problem9 = product $ head [ [a,b,c] | a <- [1..999], b <- [1..a], let c = 1000 - a - b, a^2 + b^2 == c^2]

The next one is even easier:

Problem 10:
Find the sum of all the primes below two million.

We already covered a method for generating primes, so our solution is just:

problem10 = sum $ takeWhile (<2000000) primes

And now for a slightly trickier problem:

Problem 12:
What is the value of the first triangle number to have over five hundred divisors?

(Yes, I skipped over problem 11. I haven't found a good way of doing it yet.)
The triangular numbers can be easily generated using scanl1. To find the number of factors of a number, we use the following trick: find the prime factorization of the number, add 1 to each exponent in the factorization, then multiply the exponents together. This makes sense because any factor must be a combination of prime factors. So really you're evaluating all the possible combinations of exponents in the prime factorization, with each term pn having n+1 possible exponent states (since n = 0 is also a valid state).

The only real challenge here is to find a way get the exponents of each prime factor. Recall that our primeFactors function returns a unique list of prime numbers that multiply together to form the original number. So one way we can get the exponent of each number is to simply count the number of times a number appears in the list. To accomplish this, we will use a new function called span, which takes a list and a comparison as arguments and returns a tuple.

Have we covered tuples yet? A tuple is just a pair of two values. The reason they're useful is that the values can have different types, which isn't true of a list. In this case, span looks for the first element in the list that does not satisfy the comparison function, and splits the list in two at that element. The first part goes in the first value of the tuple, and the latter part goes to the second value.

Normally we could not use span to count the number of occurrences of an element in a list, but this is a special case. Since the way we defined primeFactors means that its output is in ascending order, the repeated prime factors will already be grouped together. So all we have to do is get the length of the first part, then call our function on the latter part to get the next value. Here's the implementation:

getExp [] = []
getExp xs = length (fst spanTuple) : getExp (snd spanTuple) where
    spanTuple = span (== (head xs)) xs

As you might have guessed, fst and snd are simply functions that let us access the first and second values in a tuple. Also note that we must define the base case getExp []; otherwise our function would never terminate.

Now that we have our list of exponents, it is a simple matter to add 1 to them and take the product. Then we simply run this calculation on each triangular number and perform a list comprehension:

problem12 = head [x | x <- triangles, numFactors x > 500] where
    triangles = scanl1 (+) [1..]
    numFactors = product . getExp . primeFactors
    getExp [] = []
    getExp xs = length (fst spanTuple) : getExp (snd spanTuple) where
        spanTuple = span (== (head xs)) xs

Note that we have defined numFactors in pointfree style here.

Originally I used group to count the number of occurrences, but it seemed unnecessarily verbose. Fortunately, Haskell makes it easy to define custom-tailored functions like getExp inline, right where you need them.

One thoughts on “euler !! 5

  1. This has nothing to do with your present blog, but wanted to take the time to thank you for your comment on the Esquire template (http://btemplates.com/2012/blogger-template-esquire/) - I finally understand why I couldn't change anything - very helpful! Thanks for helping a very frazzled person!

    ReplyDelete

Theme: Esquire by Matthew Buchanan.