Saturday, May 8, 2010

Problem 4: Find the largest palidromic number made from the product of two 3-digit numbers.

First we implement a function for determining whether a number is palindromic.  We use an efficient tail recursive algorithm comparing the string converted number by character indices working from either end of the string until we reach the middle.

let isPalindrome n =
    let rec isPalindrome (nstr:string) i j =
        if i > j then true 
        elif  nstr.[i] <> nstr.[j] then false
        else isPalindrome nstr (i+1) (j-1)
    let nstr = n |> string
    isPalindrome nstr 0 (nstr.Length - 1)

Now we just need to enumerate all products made from two 3-digit (100 through 999) numbers, taking the max of those which are palindromic.  Solution (a) uses an imperative approach justifiable in nested loop scenarios while (b) and (c) use sequence expressions and typical function applications.

//fastest, reasonable use of iterative loop + mutable
let problem4a =        
    let mutable max = 0
    for i in 100..999 do
        for j in 100..999 do
            let p = i * j
            if p > max && p |> isPalindrome then max <- p    
    max

//notably slower since has to process isPalindrome for every possibility
let problem4b =
    seq { for i in 100..999 do for j in 100..999 do yield i * j }
    |> Seq.filter isPalindrome
    |> Seq.max

//still lower than 4a
let problem4c =
    seq { for i in 100..999 do for j in 100..999 do yield i * j }
    |> Seq.fold (fun acc i -> if i > acc && i |> isPalindrome then i else acc) 0

While (b) is the clearest, I like solution (a) the best since it’s clear enough and notably faster than either (b) or (c).

1 comment:

  1. Good use of a mutable! It's certainly a lot faster than building up a list of the possible answers and getting the maximum at the end.

    Couple of improvements could be made though, potentially halving the CPU time.

    (i) Run the j loop from 100 to i, not 999. That way you avoid checking the same product twice, e.g. 100*101 and 101*100.

    (ii) Before checking that p is in fact palindromic, first check that p is greater than 99,999, i.e. that it contains six figures, as it's fair to assume that there'll be at least one six-digit palindromic product. In fact there are 489! As to the five-digit ones, there are 750 of these, so they're worth dispensing with early.



    ReplyDelete