HR F#: Pascal's Triangle

HR F#: Pascal's Triangle

The second problem from the Recursive subdomain is printing Pascal's Triangle for given n.

Pascal's triangle is named after famous French mathematician from XVII century, Blaise Pascal. His findings on the properties of this numerical construction were published in this book, in 1665. Year before Great Fire of London.

The first row of the triangle is just one. (N+1)th row is constructed from Nth row by prepending and appending the sums of pairs from the Nth row with 1s:

row(0) =     1
row(1) =    1 1
row(2) =   1 2 1
row(3) =  1 3 3 1
row(4) = 1 4 6 4 1
row(n+1) = 1 (row(n)[0]+row(n)[1]) (row(n)[1]+row(n)[2]) ... 1

The k-th element of the n-th row can be calculated by n!/(k! (n-k)!) so the straightforward solution is just a single for with a factorial routine:

let rec f n =
    match n with | 0 | 1 -> 1 | _ -> n * f (n-1)
let line n =
  seq { for k in 0..n do yield ((f n) / ((f k) * f (n-k))) }

This solution works well for the test data but it is a bit inefficient (to be precise, its complexity O(n^2)) Multiplication is quite heavy and there is definitely room for improvements. For example, calculating the factorials can be replaced with lookup from pre-build table.

open System

let buildFactorialTable n =
  let rec build v i =
    seq { if i <= n then
            yield (i * v)
            yield! build (i * v) (i + 1) }
  (1 :: (build 1 1 |> Seq.toList)) |> List.toArray

let line (ft : int array) n =
  seq { for k in 0..n do yield (ft.[n] / ((ft.[k]) * (ft.[n-k]))) }

[<EntryPoint>]
let main argv =
  let n = Console.ReadLine() |> int
  let factorialTable = buildFactorialTable n
  for i in 0..(n-1) do
    printfn "%s"  (String.Join (" ", line factorialTable i |> Seq.map string))
  0 // return an integer exit code

Although it also works well, it only can calculate a few lines of the triangle. This is due to fact that factorial grows very quickly.

So the best solution is to generate next line directly from the previous:

open System

let lines n =
  let rec build (prev : int list) i =
    [ if i < n then
        let line = [ yield 1
                     for p in Seq.pairwise prev do
                       yield (fst p) + (snd p)
                     yield 1 ]
        yield line
        yield! build line (i+1) ]
  [ yield [1]; yield! build [1] 1 ]

[<EntryPoint>]
let main argv =
  let n = Console.ReadLine() |> int
  lines n
  |> Seq.iter (fun line -> printfn "%s" (String.Join (" ", line |> Seq.map string)))
  0 // return an integer exit code