I found quite a concise answer online that seems to be faster than the above. I haven't fully got my head round it so if someone could shed some light onto the mathematics behind this solution and why it processes faster I'd really appreciate it. Any further information on how this technique could be utilised for other problems would also be very helpful.
def total_nums(x)
xf, nf, tf = (1..x).inject(1,:*), (1..9).inject(1,:*), (1..x+9).inject(1,:*)
(x+10)*tf/xf/nf/10 + tf/xf/nf - 10*x - 1
end
When doing a Benchmark comparison test, it certainly shows the difference in processing speed for these two results. If I tried a greater method call than total_nums(6)
for the 1st method it would take too long. Here's the result for those interested.
require 'benchmark'
def total_nums x
return 0 if x == nil
return 1 if x == 0
1.upto(10 ** x).count do |i|
s = i.to_s.chars
t = s.sort
s == t || s == t.reverse
end
end
def total_nums2(x)
xf, nf, tf = (1..x).inject(1, :*), (1..9).inject(1, :*), (1..(x + 9)).inject(1, :*)
( ((x + 10) * tf) /xf/nf/10) + (tf/xf/nf) - (10 * x) - 1
end
Benchmark.bm do |x|
x.report { puts total_nums(6) }
#=> user system total real
#=> 12952
#=> 2.720000 0.010000 2.730000 ( 2.760713)
x.report { puts total_nums2(6) }
#=> user system total real
#=> 12952
#=> 0.000000 0.000000 0.000000 ( 0.000049)
end