Project Euler in F# – Problem 55
As in the last post, in the description of Project Euler problem 55 there is a detailed step-by-step solution of the problem itself and we just have to write the F# code to perform the tasks.
The only thing that I really had to understand is the definition of Lychrel numbers:
If we take 47, reverse and add, 47 + 74 = 121, which is palindromic.
Not all numbers produce palindromes so quickly. For example,
349 + 943 = 1292,
1292 + 2921 = 4213
4213 + 3124 = 7337That is, 349 took three iterations to arrive at a palindrome.
Although no one has proved it yet, it is thought that some numbers, like 196, never produce a palindrome. A number that never forms a palindrome through the reverse and add process is called a Lychrel number. Due to the theoretical nature of these numbers, and for the purpose of this problem, we shall assume that a number is Lychrel until proven otherwise. In addition you are given that for every number below ten-thousand, it will either (i) become a palindrome in less than fifty iterations, or, (ii) no one, with all the computing power that exists, has managed so far to map it to a palindrome. In fact, 10677 is the first number to be shown to require over fifty iterations before producing a palindrome: 4668731596684224866951378664 (53 iterations, 28-digits).
Surprisingly, there are palindromic numbers that are themselves Lychrel numbers; the first example is 4994.
How many Lychrel numbers are there below ten-thousand?
As usual, it is suggested to break down the problem into little pieces that can be easily solved with a few lines of code each.
First, we need a function to reverse an integer and another one to check whether a number is palindromic, i.e. it is equal to its reverse.
Then we define a function that will be used during each iteration to take a number and sum it with its reverse. This new number is the one that will be checked next for being a palindrome inside the isLychrel function.
If we found a palindrome then the number under testing is not a Lychrel, otherwise we can start the next iteration up to a maximum of 50 times. If we hit this limit then we can conclude the number is a Lychrel.
We have now all the pieces required to answer the original question. Just take all numbers smaller then 10000, filter the Lychrel ones and count them:
#light
let reverse n =
n.ToString().ToCharArray()
|> Array.rev
|> Array.map (fun x -> x.ToString())
|> Array.reduce_left (^)
|> bigint.Parse
let isPalindromic n =
n = reverse n
let reverseAndAdd n =
n + reverse n
let isLychrel n =
let rec isLychrelIter n i =
match i with
| 50 -> true
| _ ->
let r = reverseAndAdd n
if isPalindromic r then
false
else
isLychrelIter r (i+1)
isLychrelIter n 1
let answer = [1I .. 10000I]
|> Seq.filter (fun x -> isLychrel x)
|> Seq.length
claudio on December 17th 2008 in Project Euler
Matt responded on 18 Dec 2008 at 6:14 am #
Nice work!
3 quick things:
You can extend the String module with a “reverse” method since string implements Seq:
module String =
let reverse (s : string) =
new string(s |> Array.of_seq |> Array.rev)
Then your reverse method can be written more concisely:
let reverse (n : Math.BigInt) =
n |> string |> String.reverse |> bigint.Parse
Also, for the filter at the end, you can just write it as:
|> Seq.filter isLychrel