The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
Ruby: Running time = 0.1s
+-#PrimeList
class PrimeList
@@primes=[2,3,5,7,11,13,17,19]
def initialize
@next=-1
end
def last
return 0 if @next==-1
PrimeList.get(@next)
end
def getNext
PrimeList.get(@next+=1)
end
def [](i)
PrimeList.get(i)
end
def PrimeList.isPrime?(n)
if(@@primes[-1] >= n)
return true if @@primes.index n
return false
end
p=PrimeList.new
sq=Math.sqrt(n)
while(p.last<=sq)
return false if n % (p.getNext)==0
end
true
end
def PrimeList.get(i)
PrimeList.gen while @@primes.length<=i
@@primes[i]
end
def PrimeList.getPrimeNear(n)
PrimeList.gen until n<@@primes[-1]
@@primes[PrimeList.primeIndexNear(n)]
end
private
def PrimeList.primeIndexNear(n)
return 0 if n<@@primes[0]
return [-1] if n>@@primes[-1]
PrimeList.getIndexNear(@@primes,n)
end
def PrimeList.getIndexNear(list,n)
return 0 if list.length==1
if(list.length==2)
avg=(list[0]+list[1])/2.0
return 1 if n>avg
return 0
end
splitAfter=list.size/2
return PrimeList.getIndexNear(list[0..splitAfter],n) if n<list[splitAfter]
return splitAfter+1+PrimeList.getIndexNear(list[(splitAfter+1)..-1],n) if n>list[splitAfter+1]
avg=(list[splitAfter]+list[splitAfter+1])/2
return splitAfter+1 if n>avg
splitAfter
end
def PrimeList.gen
add=@@primes[-1]
cands=Set.new(1..(5*add)){|i|2*i+add}
theBegin=add+2
theEnd=11*add
highest=Math.sqrt(theEnd).to_i
upTo=PrimeList.primeIndexNear(highest)
upTo-=1 if @@primes[upTo]>highest
@@primes[1..upTo].each do |mult|
((theBegin-theBegin%mult)..(theEnd-theEnd%mult + mult)).step(mult){|i|cands.delete i}
end
@@primes=@@primes+cands.to_a.sort
end
end
+-#Enumerable
module Enumerable
def sum
self.inject{|u,v|u+v}
end
def product
self.inject{|u,v|u*v}
end
def count(ob)
self.select{|i|i==ob}.length
end
def take_while
return [] unless yield(self.first)
if(self.class==Range)
evalPoint=self.first
evalPoint=evalPoint.succ while yield(evalPoint.succ) and not evalPoint==self.last
return self.first..evalPoint
else
s=self.to_a
upTo=1
upTo+=1 while yield(s[upTo]) and upTo<self.length
return self[0...upTo]
end
end
end
def is_truncatable?(s)
n=s.to_i
return false if n<10
return false unless PrimeList.isPrime? n
(1..(s.length-1)).all?{|l|PrimeList.isPrime?(s[0...l].to_i) and PrimeList.isPrime?(s[(s.length-l)..-1].to_i)}
end
def truncatable_from(s,l)
return [s.to_i].to_set if l==0 and is_truncatable?(s)
return Set.new if l==0
ret= (1..9).map{|i|s+i.to_s}.select{|ss|PrimeList.isPrime?(ss.to_i)}.map{|ss|truncatable_from(ss,l-1)}
return Set.new unless ret.length > 0
return ret.inject{|u,v|u+v}
end
def p37
answers=Set.new
len=0
while answers.size<11
len+=1
[2,3,5,7].each do |p|
answers+=truncatable_from(p.to_s,len)
end
end
puts answers.sum
end