Project Euler – Problem 4 Solution

Problem

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

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

Solution

open System.Linq

let isPalindromic n =
    let charArray = n.ToString().ToCharArray()
    let revCharArray = Array.rev charArray
    charArray.SequenceEqual(revCharArray)

let numbers = [100..999]
let products = numbers |> List.collect (fun x -> numbers |> List.map (fun y -> x * y))
let maxPalindromic = products |> Seq.filter isPalindromic |> Seq.max

In my solution above, I first built a function to check whether a given number is palindromic by comparing the original and reversed char array representing the number and see if they’re the same, i.e. 9009 is represented by the char array [‘9′;’0′;’0′;’9’], and the reversed array is still [‘9′;’0′;’0′;’9’].

Notice how I used the Array.rev function in the isPalindromic function, it returns a new array with all the elements in reverse order. Another thing you might have noticed in this function is that I used the Enumerable.SequenceEqual Linq extension method to compare the two arrays, as I’ve mentioned before, with F# being a first class citizens of the .Net family you’re free to use whatever CLR library of your choice.

The rest of the solution might be relatively straight forward, however, you might be wondering what the List.collect function does. Like the List.map function, it applies a function to each element in the list, except that each element produces a list and all these lists are concatenated into a final list.

Now let’s see how the two differs, say we have a list of numbers from 1 to 10, and I want to find out the Cartesian product of the list multiplied by itself, i.e. 1 * 1, 1 * 2, … 1 * 10, 2 * 1, 2 * 2… 10 * 10:

let numbers = [1..10]

// List.map returns an array of array containing results of 1 *  [1..10], 2 * [1..10], etc.
numbers |> List.map (fun x -> numbers |> List.map(fun y -> x * y));;
val it : int list list =
[[1; 2; 3; 4; 5; 6; 7; 8; 9; 10];
 [2; 4; 6; 8; 10; 12; 14; 16; 18; 20];
 [3; 6; 9; 12; 15; 18; 21; 24; 27; 30];
 [4; 8; 12; 16; 20; 24; 28; 32; 36; 40];
 [5; 10; 15; 20; 25; 30; 35; 40; 45; 50];
 [6; 12; 18; 24; 30; 36; 42; 48; 54; 60];
 [7; 14; 21; 28; 35; 42; 49; 56; 63; 70];
 [8; 16; 24; 32; 40; 48; 56; 64; 72; 80];
 [9; 18; 27; 36; 45; 54; 63; 72; 81; 90];
 [10; 20; 30; 40; 50; 60; 70; 80; 90; 100]]

// List.collect returns a 1-dimensional array instead
numbers |> List.collect (fun x -> numbers |> List.map (fun y -> x * y));;
val it : int list =
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 3; 6; 9;
 12; 15; 18; 21; 24; 27; 30; 4; 8; 12; 16; 20; 24; 28; 32; 36; 40; 5; 10; 15;
 20; 25; 30; 35; 40; 45; 50; 6; 12; 18; 24; 30; 36; 42; 48; 54; 60; 7; 14;
 21; 28; 35; 42; 49; 56; 63; 70; 8; 16; 24; 32; 40; 48; 56; 64; 72; 80; 9;
 18; 27; 36; 45; 54; 63; 72; 81; 90; 10; 20; 30; 40; 50; 60; 70; 80; 90; 100]
  • Pingback: Project Euler — Problem 36 Solution | theburningmonk.com()

  • Omu

    my solution:
    let reverseNumber n =
    let rec loop acc = function
    |0 -> acc
    |x -> loop (acc * 10 + x % 10) (x/10)
    loop 0 n

    let isPalindrome = function
    | x when x = reverseNumber x -> true
    | _ -> false

    let max =[for a in 100 .. 999 do
    for b in 100 .. 999 do yield a*b]
    |> Seq.filter (fun x -> isPalindrome x)
    |> Seq.max