Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unlucky number 13

Tags:

python

I came across this problem Unlucky number 13! recently but could not think of efficient solution this.

Problem statement :

N is taken as input.

N can be very large 0<= N <= 1000000009

Find total number of such strings that are made of exactly N characters which don't include "13". The strings may contain any integer from 0-9, repeated any number of times.

# Example:

# N = 2 :
# output : 99 (0-99 without 13 number)

# N =1 :
# output : 10 (0-9 without 13 number)

My solution:

N = int(raw_input())

if N < 2:
    print 10

else:
    without_13 = 10

    for i in range(10, int('9' * N)+1):
        string = str(i)
        if string.count("13") >= 1:
            continue
        without_13 += 1
    print without_13

Output

The output file should contain answer to each query in a new line modulo 1000000009.

Any other efficient way to solve this ? My solution gives time limit exceeded on coding site.

like image 710
Kishan Mehta Avatar asked Oct 05 '16 08:10

Kishan Mehta


People also ask

What is the unluckiest number?

This fear of the unknown would seem to play into two other popular theories for the number's unlucky connotation, both of which revolve around the appearance of a 13th guest at two ancient events: In the Bible, Judas Iscariot, the 13th guest to arrive at the Last Supper, is the person who betrays Jesus.

Is 13 a bad number in India?

The number 13 is actually a very lucky number. In fact, in India, the 13th day of the lunar fortnight is known to be highly auspicious and is called Triyodashi. It belongs to Lord Shiva and is said to bestow long life, peace and good fortune.

Why is the number 13 Afraid?

The most popular theory about the origin of fear of the number 13 is biblical: there were 13 diners at the Last Supper. The 13th to arrive was Judas, who betrayed Jesus. In Norse mythology, too, a table of 13 proved unlucky, to say the least.

What does the lucky number 13 mean?

The sacred number 13 is considered to be a very karmic number in numerology. It is associated with the divine, and is said to bring good luck and prosperity to those who embrace it. In fact, many people believe that the number 13 brings about change, which can often lead to a positive outlook.


2 Answers

I think this can be solved via recursion:

ans(n) = { ans([n/2])^2 - ans([n/2]-1)^2 }, if n is even
ans(n) = { ans([n/2]+1)*ans([n/2]) - ans([n/2])*ans([n/2]-1) }, if n is odd

Base Cases:

  • ans(0) = 1
  • ans(1) = 10

It's implementation is running quite fast even for larger inputs like 10^9 ( which is expected as its complexity is O(log[n]) instead of O(n) like the other answers ):

cache = {}

mod = 1000000009

def ans(n):
    if cache.has_key(n):
        return cache[n]

    if n == 0:
        cache[n] = 1
        return cache[n]
    if n == 1:
        cache[n] = 10
        return cache[n]

    temp1 = ans(n/2)
    temp2 = ans(n/2-1)

    if (n & 1) == 0:
        cache[n] = (temp1*temp1 - temp2*temp2) % mod
    else:
        temp3 = ans(n/2 + 1)
        cache[n] = (temp1 * (temp3 - temp2)) % mod

    return cache[n]

print ans(1000000000)

Online Demo

Explanation:

Let a string s have even number of digits 'n'.
Let ans(n) be the answer for the input n, i.e. the number of strings without the substring 13 in them.
Therefore, the answer for string s having length n can be written as the multiplication of the answer for the first half of the string (ans([n/2])) and the answer for the second half of the string (ans([n/2])), minus the number of cases where the string 13 appears in the middle of the number n, i.e. when the last digit of the first half is 1 and the first digit of the second half is 3.

This can expressed mathematically as:

ans(n) = ans([n/2])^2 - ans([n/2]-1)*2

Similarly for the cases where the input number n is odd, we can derive the following equation:

ans(n) = ans([n/2]+1)*ans([n/2]) - ans([n/2])*ans([n/2]-1)
like image 89
Anmol Singh Jaggi Avatar answered Sep 18 '22 00:09

Anmol Singh Jaggi


Let f(n) be the number of sequences of length n that have no "13" in them, and g(n) be the number of sequences of length n that have "13" in them.

Then f(n) = 10^n - g(n) (in mathematical notation), because it's the number of possible sequences (10^n) minus the ones that contain "13".

Base cases:

f(0) = 1
g(0) = 0
f(1) = 10
g(1) = 0

When looking for the sequences with "13", a sequence can have a "13" at the beginning. That will account for 10^(n-2) possible sequences with "13" in them. It could also have a "13" in the second position, again accounting for 10^(n-2) possible sequences. But if it has a "13" in the third position, and we'd assume there would also be 10^(n-2) possible sequences, we could those twice that already had a "13" in the first position. So we have to substract them. Instead, we count 10^(n-4) times f(2) (because those are exactly the combinations in the first two positions that don't have "13" in them).

E.g. for g(5):

g(5) = 10^(n-2) + 10^(n-2) + f(2)*10^(n-4) + f(3)*10^(n-5)

We can rewrite that to look the same everywhere:

g(5) = f(0)*10^(n-2) + f(1)*10^(n-3) + f(2)*10^(n-4) + f(3)*10^(n-5)

Or simply the sum of f(i)*10^(n-(i+2)) with i ranging from 0 to n-2.

In Python:

from functools import lru_cache

@lru_cache(maxsize=1024)
def f(n):
    return 10**n - g(n)

@lru_cache(maxsize=1024)
def g(n):
    return sum(f(i)*10**(n-(i+2)) for i in range(n-1))  # range is exclusive

The lru_cache is optional, but often a good idea when working with recursion.


>>> [f(n) for n in range(10)]
[1, 10, 99, 980, 9701, 96030, 950599, 9409960, 93149001, 922080050]

The results are instant and it works for very large numbers.

like image 20
L3viathan Avatar answered Sep 20 '22 00:09

L3viathan