Project Euler problem 49

Prime permutations

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?

Link to original description
Source code examples on Github

first brutforce solution with erlang:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p49
% vim:syn=erlang

-mode(compile).

main(_) ->
    L = lists:filter(fun(1487)->false;(4817)->false;(8147)->false;(E) when E > 999 -> true;(_) -> false end, prime(10000)),
    Fn = fun(E) -> 
        M = lists:map(fun(D)  -> list_to_integer(D) end,
               lists:usort(fun(A,B) when A > B -> true;(_,_) -> false end,
                  lists:filter(fun(G)-> lists:member(list_to_integer(G), L) end,
                     permutant(integer_to_list(E))))),
        case length(M) of
            N when N > 3 -> lists:member(true, [ check_seq(IL,E) || IL <- combos(M)]);
            3            -> check_seq(M,E);
            _            -> false
        end
    end,
    Answer = lists:filter(Fn, L),
    io:format("Answer: ~p ~n", [Answer]).

check_seq([A,B,C],E) when B-A =:= C-B -> lists:member(E, [A,B,C]);
check_seq(_,_)                        -> false.
permutant([])                         -> [ []];
permutant(L)                          -> [ [H|T] || H <- L, T <- permutant(L--[H]) ].
combos(L)                             -> [ [A,B,C] || A <- L, B <- L, C <- L, A=/=B,A=/=C,B=/=C,A < B,B < C ].

prime(2)                    -> [2] ;
prime(N) when N > 2, N =< 6 -> prime(lists:seq(3,N,2),[2]);
prime(N) when N > 6         -> prime(lists:merge( [6*K-1 || K <- lists:seq(1,(N+1) div 6)], [6*K+1 || K <- lists:seq(1,(N-1) div 6)] ), [2,3]);
prime(_)                    -> [].

prime(X,P)                  -> prime(X,lists:reverse(P),P).

prime([],_,P)                                          -> lists:reverse(P) ;
prime([H|T],[HP|TP],P) when HP * HP =< H,H rem HP > 0  -> prime([H|T],TP,P);
prime([H|T],[HP|_],P)  when HP * HP > H                -> prime(T,[H|P]);
prime([_|T],_,P)                                       -> prime(T,P).

Now lets try to optimize algorithm. We are have to find 3 numbers: I,J,K I<J<K. And:

J = I + N
K = J +N 

So K = J + (J - I) , because N = J - I.

and we are have more optimal solution wuth erlang:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p49_1
% vim:syn=erlang

-mode(compile).

main(_) ->
    L = lists:filter(fun(E) when E > 1487 -> true;(_) -> false end, prime(10000)),
    io:format("Answer: ~p ~n", [get_i(L)]).

get_i([])    -> [];
get_i([I|T]) -> 
    case get_j(I, T) of
        [] -> get_i(T);
        R  -> R
    end.

get_j(_,    []) -> [];
get_j(I, [J|T]) ->
    Is = lists:sort(integer_to_list(I)),
    case lists:sort(integer_to_list(J)) == Is of
        true  -> 
            K = 2*J-I,
            case lists:sort(integer_to_list(K)) == Is of
                true ->
                    case lists:member(K, T) of
                        true -> [I,J,K] 
                        ;_   -> get_j(I, T)
                    end
                ;_ -> get_j(I, T)
            end;
        false -> get_j(I, T)
    end.


prime(2)                    -> [2] ;
prime(N) when N > 2, N =< 6 -> prime(lists:seq(3,N,2),[2]);
prime(N) when N > 6         -> prime(lists:merge( [6*K-1 || K <- lists:seq(1,(N+1) div 6)], [6*K+1 || K <- lists:seq(1,(N-1) div 6)] ), [2,3]);
prime(_)                    -> [].

prime(X,P)                  -> prime(X,lists:reverse(P),P).

prime([],_,P)                                          -> lists:reverse(P) ;
prime([H|T],[HP|TP],P) when HP * HP =< H,H rem HP > 0  -> prime([H|T],TP,P);
prime([H|T],[HP|_],P)  when HP * HP > H                -> prime(T,[H|P]);
prime([_|T],_,P)                                       -> prime(T,P).

and same algorithm with python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/python3

import prime

def t49():
    for n,i in enumerate(prime.prime_list):
        if i < 1488: continue
        m, ml   = n+1, len(prime.prime_list)
        ist = sorted(str(i))
        while True:
            if m >= ml: break
            j = prime.prime_list[m]
            if(sorted(str(j)) == ist):
                k = 2*j-i
                if(sorted(str(k)) == ist and prime.isprime(k)): return [i, j, k]
            m += 1
    return [0,0,0]


MAX = 10000
prime._refresh(MAX)
print("Answer: %s" % t49())