Problem
The chess knight has a unique movement, it may move two squares vertically and one square horizontally, or two squares horizontally and one square vertically (with both forming the shape of an L). The possible movements of chess knight are shown in this diagaram:
A chess knight can move as indicated in the chess diagram below:
We have a chess knight and a phone pad as shown below, the knight can only stand on a numeric cell (i.e. blue cell).
$$ \begin{bmatrix} \colorbox{blue} 1 & \colorbox{blue} 2 & \colorbox{blue} 3 \\ \colorbox{blue} 4 & \colorbox{blue} 5 & \colorbox{blue} 6 \\ \colorbox{blue} 7 & \colorbox{blue} 8 & \colorbox{blue} 9 \\ \colorbox{red} * & \colorbox{blue} 0 & \colorbox{red} \# \end{bmatrix} $$
Given an integer n
, return how many distinct phone numbers of length n
we can dial.
You are allowed to place the knight on any numeric cell initially and then you should perform n - 1
jumps to dial a number of length n
. All jumps should be valid knight jumps.
As the answer may be very large, return the answer modulo 10^9 + 7
.
Examples
Example 1:
|
|
Example 2:
|
|
Example 3:
|
|
Solution
Method 1 - Recursion
The knight can only stand on numeric keys (blue cells), and it moves in an “L” shape, which means:
- Two squares in one direction and one square perpendicular, or
- One square in one direction and two squares perpendicular.
Based on that we can we define moves[]
matrix. Then for each element moves[i]
we get following knight moves:
- from
0
we can either go to cells4
or6
. Hencemoves[0] = [4, 6]
- from
1
we can either go to cells6
or8
. Hencemoves[1] = [6, 8]
So, this is how we can define our moves:
|
|
Code
|
|
Complexity
- ⏰ Time complexity:
O(9^n)
- For each digit, the knight can make up to 2 or 3 jumps based on the
moves
array. - Let
f(n, d)
be the number of ways to reach a number of lengthn
starting at digitd
. - Without memoization, the total number of calls can be very large as it forms a tree-like structure.
- In general, for
n
moves, the number of recursive calls can be approximated byO(9^n)
in the worst case, because of the overlapping subproblems and exponential growth in recursive calls.
- For each digit, the knight can make up to 2 or 3 jumps based on the
- 🧺 Space complexity:
O(n)
, assuming recursion stack
Method 2 - Top Down DP with memo
Code
|
|
Complexity
- ⏰ Time complexity:
O(n)
- Each state
(n, d)
is computed at most once and stored inmemo
. - There are
10*n
possible states. - For each state
(n, d)
, we iterate over a constant list of knight moves (at most 3 moves). So, we getO(10*n)
=O(n)
- Each state
- 🧺 Space complexity:
O(n)
- The memoization table, which stores results for all states
(n, d)
, which takesO(10n)
- The recursion stack depth, which is
n
.
- The memoization table, which stores results for all states
Method 3 - Bottom up DP
The idea is to track the number of ways to reach each numeric cell on the phone pad with a certain number of moves, leveraging the unique movement capabilities of a chess knight.
Here are the steps we can take:
-
Initialization:
- Create a DP table where
dp[i][j]
represents the number of ways to reach cellj
withi
moves. - Initialize the base cases where
dp[0][j] = 1
for all numeric keysj
(since there is 1 way to be on a key initially without any moves).
- Create a DP table where
-
Valid Moves:
- Define the possible knight moves from each numeric cell. These are the valid transitions based on knight’s movement rules.
-
DP Transition:
- Update the DP table based on possible moves. For each move count
i
, updatedp[i+1]
(next move count) based on current move countdp[i]
using the valid knight moves.
- Update the DP table based on possible moves. For each move count
-
Result Calculation:
- Sum the number of ways to end up on any numeric key after
n-1
moves (since another move is required to reach a phone number of lengthn
).
- Sum the number of ways to end up on any numeric key after
-
Modulo Operation:
- Since the result can be large, take the result modulo (10^9 + 7).
Code
|
|
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)