Project Euler – Problem 49 Solution

Yan Cui

I help clients go faster for less using serverless technologies.

This article is brought to you by

MongoDB 8.0 is here to change the game. Faster reads and inserts, and brand-new vector search to support modern AI-powered apps.

Learn More

Problem

The arithmetic sequence, 1487, 4817, 8147, in which each of the terms increases by 3330, is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the 4-digit numbers are permutations of one another.

There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, exhibiting this property, but there is one other 4-digit increasing sequence.

What 12-digit number do you form by concatenating the three terms in this sequence?

Solution

open System.Collections

let rec distribute e = function
    | [] -> [[e]]
    | x::xs' as xs -> (e::xs)::[for xs in distribute e xs' -> x::xs]

let rec permute = function
    | [] -> [[]]
    | e::xs -> List.collect (distribute e) (permute xs)

let rec comb n l =
    match n, l with
    | 0, _ -> [[]]
    | _, [] -> []
    | k, (x::xs) -> List.map ((@) [x]) (comb (k-1) xs) @ comb k xs

let max = 9999

// define a cache for holding records of which number is a prime
let cache = new BitArray(max+1, true)

// using prime sieve to fill out the cache
[2..max]
    |> List.iter (fun n ->
        if cache.[n] then
            [2..max]
            |> Seq.takeWhile (fun m -> n * m <= max)
            |> Seq.iter (fun m -> cache.[n * m]  List.filter (fun n -> cache.[n])

// define function to get the 4-digit prime permutations of a number
let getPrimePermutations n =
    let digitsStr = n.ToString().ToCharArray() |> Array.map string
    Array.toList digitsStr
    |> permute
    |> Seq.distinct
    |> Seq.map (fun chars -> int(chars |> List.reduce (+)))
    |> Seq.filter (fun x -> x >= 1000 && cache.[x])
    |> Seq.sort
    |> Seq.toList

let answer =
    primeNumbers
    |> List.map getPrimePermutations
    |> List.filter (fun l -> l |> List.length >= 3)
    |> Seq.distinct
    |> Seq.toList
    |> List.map (fun l -> comb 3 l |> List.filter (fun l' -> l'.[1] - l'.[0] = l'.[2] - l'.[1]))
    |> List.filter (fun l -> l |> List.length > 0)

The above solution returns two lists:

val answer : int list list list = [[[1487; 4817; 8147]]; [[2969; 6299; 9629]]]

The first of course, correlates to the example given in the brief, the other, is the base for your answer!

Whenever you’re ready, here are 3 ways I can help you:

  1. Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
  2. I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
  3. Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.

Leave a Comment

Your email address will not be published. Required fields are marked *