Dynamic Programming · 53 of 60
Mobile Numeric Keypad Problem
Count how many numbers of length n you can type on an old phone keypad if every press stays on the same key or moves to a key that touches it.
- Simple way
- time O(5^n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
An old phone has a keypad with four rows: 1 2 3, 4 5 6, 7 8 9, and * 0 #. You must press exactly n keys. The first press can be any digit. After that, every press must be the same key again, or a key right next to it: up, down, left or right. Never sideways at a slant. The * and # keys are not allowed.
Give back how many different numbers of length n you can type.
A story to remember it
Picture it
The keypad as a grid. From 5 you can press 5 again or 2, 4, 6, 8. The grey * and # keys are never used.
- looking now
- checking
- ignored
Some keys and the keys you may press after them (the key itself included):
- 0 can go to 0 or 8, so 2 choices.
- 1 can go to 1, 2 or 4, so 3 choices.
- 2 can go to 2, 1, 3 or 5, so 4 choices.
- 5 can go to 5, 2, 4, 6 or 8, so 5 choices.
- 8 can go to 8, 5, 7, 9 or 0, so 5 choices.
Examples
One press
- In
n = 1- Out
10
Each of the ten digits is a number on its own.
Two presses
- In
n = 2- Out
36
Add up the counts of next keys for every digit: 2 + 3 + 4 + 3 + 4 + 5 + 4 + 3 + 5 + 3 = 36. For example 00, 08, 55, 52 and 80 all count.
Three presses
- In
n = 3- Out
138
The number grows fast. The walkthrough below builds it row by row.
No presses
- In
n = 0- Out
0
Most versions of this problem say there is nothing to type, so the answer is 0. Ask your interviewer, because some say 1 (the empty number).
Way 1: the simple way
Ask a helper: "starting on this key, with this many presses left, how many numbers can I make?"
- If only 1 press is left, the answer is 1. You press the key you are on and stop.
- Otherwise, try every next key (the key itself and its touching keys) and add up what the helper says for each one with one press fewer.
- Do this for all ten starting keys and add the answers.
Starting on key 0 with 3 presses. Each circle is (key, presses left), and the tag on a line is the key pressed next. The highlighted circles are asked more than once: (0, 1) and (8, 1). For bigger n the repeats explode.
- checking
class Solution {
// For each key: the keys you may press next, the key itself first
int[][] next = {
{0, 8}, // 0
{1, 2, 4}, // 1
{2, 1, 3, 5}, // 2
{3, 2, 6}, // 3
{4, 1, 5, 7}, // 4
{5, 2, 4, 6, 8}, // 5
{6, 3, 5, 9}, // 6
{7, 4, 8}, // 7
{8, 5, 7, 9, 0}, // 8
{9, 6, 8} // 9
};
public long getCount(int n) {
if (n <= 0) return 0;
long total = 0;
for (int key = 0; key <= 9; key++) {
total += count(key, n);
}
return total;
}
private long count(int key, int left) {
if (left == 1) return 1; // press this key and stop
long ways = 0;
for (int k : next[key]) {
ways += count(k, left - 1); // try every next key
}
return ways;
}
}How long it takes: each call can branch into up to 5 calls, and the calls go n levels deep, so about O(5^n). Extra room: the helpers waiting on each other, O(n).
Way 2: the clever way
The answer for (key, presses) only depends on the answers for (neighbor keys, presses minus 1). So fill a table one row at a time, like the frog numbers on the stones.
- Row for 1 press: every key gets 1.
- Row for
ppresses: for each key, add the numbers in the row above under that key and its touching keys. - The answer is the sum of the last row.
You only ever look at the row right above, so two rows of ten numbers are enough.
Fill the table one row of presses at a time
01 / 10
With one press there is exactly one number per key: the key itself. So the first row is all 1s.
- total for 1 press
- 10
- looking now
- checking
- done
- answer
- just added
- ignored
class Solution {
public long getCount(int n) {
if (n <= 0) return 0;
int[][] next = {
{0, 8}, {1, 2, 4}, {2, 1, 3, 5}, {3, 2, 6}, {4, 1, 5, 7},
{5, 2, 4, 6, 8}, {6, 3, 5, 9}, {7, 4, 8}, {8, 5, 7, 9, 0}, {9, 6, 8}
};
long[] row = new long[10];
Arrays.fill(row, 1); // 1 press: one number per key
for (int p = 2; p <= n; p++) {
long[] newRow = new long[10];
for (int key = 0; key <= 9; key++) {
for (int k : next[key]) {
newRow[key] += row[k]; // borrow from the row above
}
}
row = newRow;
}
long total = 0;
for (long ways : row) total += ways;
return total;
}
}How long it takes: each new row costs at most 10 keys times 5 neighbors, a fixed amount, so O(n) overall. Extra room: two rows of 10 numbers, O(1).
Watch out for
- Slanted moves are not allowed. 5 does not touch 1, 3, 7 or 9.
- Key 0 only touches 8, because
*and#are banned. - The numbers grow like
5^nin the worst case. Uselong, or take the answer modulo a big prime if the problem asks. - Be clear about
n = 0. Most judges expect 0.
What interviewers ask next
- Can you go faster than
O(n)for hugen? Yes. One row step is multiplying by a fixed 10 by 10 table of 0s and 1s. Raise that table to the powern - 1with repeated squaring and the work becomesO(log n). - What if the keys can also move like a chess knight? Same table filling, only the neighbor lists change. That is the famous "knight dialer" question.
- What if some digits are banned as the first press? Start the first row with 0 under those keys.
- Can you print all the numbers? Only for tiny
n, since there can be about5^nof them. Use backtracking for that.
Remember this
Grown-up words: the stones are the keypad graph, the frog numbers are a dynamic programming table dp[presses][key], keeping only the last row is space optimization, and the fast power trick is matrix exponentiation.