I came across this problem Unlucky number 13! recently but could not think of efficient solution this.
N is taken as input.
Thanks to L3viathan's comment now it is clear. The logic is beautiful.
Let's assume a(n)
is a number of strings of n
digits without "13" in it. If we know all the good strings for n-1
, we can add one more digit to the left of each string and calculate a(n)
. As we can combine previous digits with any of 10 new, we will get 10*a(n-1)
different strings. But we must subtract the number of strings, which now starts with "13" which we wrongly summed like OK at the previous step. There is a(n-2)
of such wrongly added strings. So a(n) = 10*a(n-1) - a(n-2)
. That is it. Such simple.
What is even more interesting is that this sequence can be calculated without iterations with a formula https://oeis.org/A004189 But practically that doesn't helps much, as the formula requires floating point calculations which will lead to rounding and would not work for big n (will give answer with some mistake).
Nevertheless the original sequence is quite easy to calculate and it doesn't need to store all the previous values, just the last two. So here is the code
def number_of_strings(n):
result = 0
result1 = 99
result2 = 10
if n == 1:
return result2
if n == 2:
return result1
for i in range(3, n+1):
result = 10*result1 - result2
result2 = result1
result1 = result
return result
This one is several orders faster than my previous suggestion. And memory consumption is now just O(n)
P.S. If you run this with Python2, you'd better change range
to xrange