Предположим, мы хотим идентифицировать все палиндромы между from = 27
и to = 3345
. Вместо того, чтобы исследовать каждое число от from
до to
, чтобы определить палиндромы, я сгенерирую все палиндромы между 20
и 3999
рекурсивно и комбинаторно, а затем использую два двоичных поиска, чтобы исключить все палиндромы между 20
и 26
(то есть, только 22
) и все палиндромы между 3346
и 3999
.
Код
def palindromes(from, to)
arr = ranges(from, to).each_with_object([]) do |(n,f,t),arr|
arr.concat(pals(n,f,t))
end.map { |a| a.join.to_i }
is = arr.bsearch_index { |n| n >= from }
ie = arr.bsearch_index { |n| n > to }
ie = ie.nil? ? arr.size-1 : ie-1
arr[is..ie]
end
def ranges(from, to)
*a, from_first_digit = from.digits
from_nbr_digits = a.size + 1
*a, to_first_digit = to.digits
to_nbr_digits = a.size + 1
(from_nbr_digits..to_nbr_digits).each_with_object([]) { |ndigits, a|
a << [ndigits, from_nbr_digits == ndigits ? from_first_digit : 1,
to_nbr_digits == ndigits ? to_first_digit : 9] }
end
def pals(ndigits, first, last)
case ndigits
when 1
(first..last).to_a
when 2
(first..last).map {|d| [d,d]}
else
a = pals(ndigits-2, 0, 9)
(first..last).each_with_object([]) { |d,arr|
a.each {|b| arr << [d,*b,d] } }
end
end
Примеры
palindromes(27, 3345)
#=> [ 33, 44, 55, 66, 77, 88, 99,
# 101, 111, 121, 131, 141, 151, 161, 171, 181, 191,
# 202, 212, 222, 232, 242, 252, 262, 272, 282, 292,
# ...
# 909, 919, 929, 939, 949, 959, 969, 979, 989, 999,
# 1001, 1111, 1221, 1331, 1441, 1551, 1661, 1771, 1881, 1991,
# 2002, 2112, 2222, 2332, 2442, 2552, 2662, 2772, 2882, 2992,
# 3003, 3113, 3223, 3333]
palindromes(1141, 3345)
#=> [ 1221, 1331, 1441, 1551, 1661, 1771, 1881, 1991,
# 2002, 2112, 2222, 2332, 2442, 2552, 2662, 2772, 2882, 2992,
# 3003, 3113, 3223, 3333]
require 'time'
t = Time.now
(a = palindromes(27, 34_564_824_166)).size
#=> 445635 (number of palindromes within range)
puts "Elapsed time = #{(Time.now-t).round(2)} seconds"
# Elapsed time = 2.77 seconds
a.first(20)
#=> [ 33, 44, 55, 66, 77, 88, 99,
# 101, 111, 121, 131, 141, 151, 161, 171, 181, 191,
# 202, 212, 222]
a.last(10)
#=> [34563836543, 34563936543, 34564046543, 34564146543, 34564246543,
# 34564346543, 34564446543, 34564546543, 34564646543, 34564746543]
Объяснение
(в разработке)