views:

627

answers:

3

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.

+8  A: 

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.

aioobe
A: 

This can be done in O(log N). Consider the keypad and the possible moves on it as a graph G(V, E) where vertices are the available digits and edges say which digits can follow which. Now for each output position i we can form a vector Paths(i) containing the number of different paths each vertex can be reached in. Now it's pretty easy to see that for a given position i and digit v, the possible paths that it can be reached through is the sum of the different paths that possible preceding digits could be reached through, or Paths(i)[v] = sum(Paths(i-1)[v2] * (1 if (v,v2) in E else 0) for v2 in V ). Now, this is taking the sum of each position the preceding vector times a corresponding position in a column of the adjacency matrix. So we can simplify this as Paths(i) = Paths(i-1) · A, where A is the adjacency matrix of the graph. Getting rid of the recursion and taking advantage of associativity of matrix multiplication, this becomes Paths(i) = Paths(1) · A^(i-1). We know Paths(1): we have only one path, to the digit 1.

The total number of paths for an n digit number is the sum of the paths for each digit, so the final algorithm becomes: TotalPaths(n) = sum( [1,0,0,0,0,0,0,0,0,0] · A^(n-1) )

The exponentiation can be calculated via squaring in O(log(n)) time, given constant time multiplies, otherwise O(M(n) * log(n)) where M(n) is the complexity of your favorite arbitrary precision multiplication algorithm for n digit numbers.

Ants Aasma
Nice use of the adjacency matrix. But note that you consider N to be the length of the phone number, while in the question the complexity is in terms of the number of available digits. With that, you get O(n^2) for calculating A to its 10th power.
Tomer Vromen
No, I think N should be the length of the phone number. How should the key-pad look for a larger number of digits?
aioobe
The complexity for arbitrarily sized keypad with arbitrary moves would be based on naive sparse matrix multiplication O(d*m*log n), where d is the number of digits and m is the total number of possible moves (m <= d^2). A grid based keypad would have O(d) possible moves, so yes if the question was in terms of keypad size, then this algorithm would be quadratic.
Ants Aasma
A: 

A simpler answer.

#include<stdio.h>

int a[10] = {2,2,2,2,3,0,3,2,2,2};
int b[10][3] = {{4,6},{6,8},{7,9},{4,8},{0,3,9},{},{1,7,0},{2,6},{1,3},{2,4}};

int count(int curr,int n)
{
    int sum = 0;
    if(n==10)
        return 1;
    else
    {
        int i = 0;
        int val = 0;
        for(i = 0; i < a[curr]; i++)
        {
            val = count(b[curr][i],n+1);
            sum += val;
        }
        return sum;
    }
}

int main()
{
    int n = 1;
    int val = count(1,0);
    printf("%d\n",val);
}

celebrate!!

Algorist
But this is exponential time, right? You don't do any DP or memoization...
aioobe