A chess knight can move as indicated in the chess diagram below:
.
This time, we place our chess knight on any numbered key of a phone pad (indicated above), and the knight makes
N-1
hops. Each hop must be from one key to another numbered key.Each time it lands on a key (including the initial placement of the knight), it presses the number of that key, pressing
N
digits total.How many distinct numbers can you dial in this manner?
Since the answer may be large, output the answer modulo
10^9 + 7
.
Example 1:
Input: 1 Output: 10
Example 2:
Input: 2 Output: 20
Example 3:
Input: 3 Output: 46
Note:
1 <= N <= 5000
Approach #1: DP. [Java]
class Solution { public int knightDialer(int N) { int mod = 1000000007; int[][][] dp = new int[N+1][5][4]; for (int j = 0; j < 4; ++j) for (int k = 0; k < 3; ++k) dp[1][j][k] = 1; dp[1][3][0] = dp[1][3][2] = 0; int[][] dirs = {{1, 2}, {1, -2}, {2, 1}, {2, -1}, {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}}; for (int k = 2; k <= N; ++k) { for (int i = 0; i < 4; ++i) { for (int j = 0; j < 3; ++j) { if (i == 3 && j != 1) continue; for (int d = 0; d < 8; ++d) { int x_ = i + dirs[d][0]; int y_ = j + dirs[d][1]; if (x_ < 0 || y_ < 0 || x_ >= 4 || y_ >= 3) continue; dp[k][i][j] = (dp[k][i][j] + dp[k-1][x_][y_]) % mod; } } } } int ans = 0; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 3; ++j) { ans = (ans + dp[N][i][j]) % mod; // System.out.print(dp[N][i][j] + " "); } // System.out.println("ans = " + ans); } return ans; } }
Analysis:
We can define dp[k][i][j] as of ways to dial and the last key is (i, j) after k steps
Note: dp[*][3][0], dp[*][3][2] are always zero for all the steps.
Init: dp[0][i][j] = 1
Transition: dp[k][i][j] = sum(dp[k-1][i+dy][j+dx]) 8 ways of move from last step.
ans = sum(dp[k])
Time complexity: O(kmn) or O(k*12*8) = O(k)
Space complexity: O(kmn) -> O(12 * 8) = O(1)
Approach #2: DP. [C++]
class Solution { public: int knightDialer(int N) { vector<vector<int>> dp(4, vector<int>(3, 1)); dp[3][0] = dp[3][2] = 0; int mod = pow(10, 9) + 7; vector<pair<int, int>> dirs = {{1, 2}, {1, -2}, {2, 1}, {2, -1}, {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}}; for (int k = 2; k <= N; ++k) { vector<vector<int>> temp(4, vector<int>(3, 0)); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 3; ++j) { if (i == 3 && j != 1) continue; for (int k = 0; k < 8; ++k) { int x_ = i + dirs[k].first; int y_ = j + dirs[k].second; if (x_ < 0 || y_ < 0 || x_ >= 4 || y_ >= 3) continue; temp[i][j] = (temp[i][j] + dp[x_][y_]) % mod; } } } dp.swap(temp); } int ans = 0; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 3; ++j) { ans = (ans + dp[i][j]) % mod; } } return ans; } };
define dp[k][i] as of ways to dial and the last key is i after k steps
init: dp[0][0:10] = 1
translation: dp[k][i] = sum(dp[k-1][j]) that j can move to i
ans: sum(dp[k])
Time complexity: O(k*10) = O(k)
Space complexity: O(k*10) -> O(10) = O(1).
Reference:
https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-935-knight-dialer/