Given a phone keypad as shown below:
1 2 3
4 5 6
7 8 9
0
How many different 10-digit numbers can be formed starting from 1? The constraint is that the movement from 1 digit to the next is similar to the movement of the Knight in a chess game.
For eg. if we are at 1 then the next digit can be either 6 or 8 if we are at 6 then the next digit can be 1, 7 or 0.
Repetition of digits are allowed - 1616161616 is a valid number.
Is there a polynomial time algorithm which solves this problem? The problem requires us to just give the count of 10-digit numbers and not necessarily list the numbers.
EDIT: I tried modeling this as a graph with each digit having 2 or 3 digits as its neighbors. Then I used DFS to navigate upto the depth of 10 nodes and then increment the count of numbers each time I reached the depth of 10. This obviously is not polynomial time. Assuming each digit had just 2 neighbors, this would have required at least 2^10 iterations.
The variable here is the number of digits. I have taken the eg. of 10 digit numbers. It could as well be n-digits.
Sure it can be done in polynomial time. It's an excellent exercise in dynamic programming or memoization.
Lets assume N (the number of digits) equals 10 for the example.
Think of it recursively like this: How many numbers can I construct using 10 digits starting from 1
?
Answer is
[number of 9-digit numbers starting from 8] +
[number of 9-digit numbers starting from 6].
So how many "9-digit numbers starting from 8" are there? Well,
[number of 8-digit numbers starting from 1] +
[number of 8-digit numbers starting from 3]
and so on. Base case is reached when you get the question "How many 1-digit numbers are there starting from X
" (and the answer is obviously 1).
When it comes to complexity, the key observation is that you reuse previously computed solutions. That is for instance, the answer to "how many 5-digit numbers starting from 3
" there are, can be used both when answering "how many 6-digit numbers are there starting from 8
" AND "how many 6-digit numbers are there starting from 4
". This reuse make the complexity collapse from exponential to polynomial.
Let's take a closer look at the complexity of a dynamic programming solution:
Such implementation would fill in a matrix in the following way:
num[1][i] = 1, for all 0<=i<=9 -- there are one 1-digit number starting from X.
for digits = 2...N
for from = 0...9
num[digits][from] = num[digits-1][successor 1 of from] +
num[digits-1][successor 2 of from] +
...
num[digits-1][successor K of from]
return num[N][1] -- number of N-digit numbers starting from 1.
The algorithm simply fills the matrix one cell at a time, and the matrix is of dimension 10*N, and thus runs in linear time.
Wrote it down from the top of my head, please correct me if there are any typos.