101 Logo
onenoughtone

Code Implementation

Knight Dialer Implementation

Below is the implementation of the knight dialer:

solution.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/**
* Calculate the number of distinct phone numbers of length n that can be dialed.
* Dynamic Programming approach.
*
* @param {number} n - Length of the phone number
* @return {number} - Number of distinct phone numbers
*/
function knightDialer(n) {
const MOD = 1000000007;
// Define the possible knight moves for each digit
const moves = [
[4, 6], // From digit 0
[6, 8], // From digit 1
[7, 9], // From digit 2
[4, 8], // From digit 3
[0, 3, 9], // From digit 4
[], // From digit 5
[0, 1, 7], // From digit 6
[2, 6], // From digit 7
[1, 3], // From digit 8
[2, 4] // From digit 9
];
// Initialize DP array
// dp[i][j] = number of distinct phone numbers of length i+1 that end with digit j
const dp = Array(n).fill().map(() => Array(10).fill(0));
// Base cases: there is one way to dial a number of length 1 for each digit
for (let j = 0; j < 10; j++) {
dp[0][j] = 1;
}
// Fill DP array
for (let i = 1; i < n; i++) {
for (let j = 0; j < 10; j++) {
// For each digit j, consider all possible previous digits that can jump to j
for (const prev of moves[j]) {
dp[i][j] = (dp[i][j] + dp[i - 1][prev]) % MOD;
}
}
}
// Calculate the final answer: sum of dp[n-1][j] for all j from 0 to 9
let result = 0;
for (let j = 0; j < 10; j++) {
result = (result + dp[n - 1][j]) % MOD;
}
return result;
}
/**
* Calculate the number of distinct phone numbers of length n that can be dialed.
* Space-Optimized Dynamic Programming approach.
*
* @param {number} n - Length of the phone number
* @return {number} - Number of distinct phone numbers
*/
function knightDialerOptimized(n) {
const MOD = 1000000007;
// Define the possible knight moves for each digit
const moves = [
[4, 6], // From digit 0
[6, 8], // From digit 1
[7, 9], // From digit 2
[4, 8], // From digit 3
[0, 3, 9], // From digit 4
[], // From digit 5
[0, 1, 7], // From digit 6
[2, 6], // From digit 7
[1, 3], // From digit 8
[2, 4] // From digit 9
];
// Initialize arrays for previous and current jumps
let prev = Array(10).fill(1); // Base case: one way to dial a number of length 1 for each digit
let curr = Array(10).fill(0);
// Fill arrays
for (let i = 1; i < n; i++) {
// Reset curr array
curr = Array(10).fill(0);
for (let j = 0; j < 10; j++) {
// For each digit j, consider all possible previous digits that can jump to j
for (const prevDigit of moves[j]) {
curr[j] = (curr[j] + prev[prevDigit]) % MOD;
}
}
// Update prev array
prev = [...curr];
}
// Calculate the final answer: sum of prev[j] for all j from 0 to 9
return prev.reduce((sum, val) => (sum + val) % MOD, 0);
}
/**
* Calculate the number of distinct phone numbers of length n that can be dialed.
* Matrix Exponentiation approach.
*
* @param {number} n - Length of the phone number
* @return {number} - Number of distinct phone numbers
*/
function knightDialerMatrix(n) {
const MOD = 1000000007;
// If n is 1, return 10 (one way to dial a number of length 1 for each digit)
if (n === 1) {
return 10;
}
// Define the adjacency matrix
const matrix = [
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0], // From digit 0
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0], // From digit 1
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1], // From digit 2
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0], // From digit 3
[1, 0, 0, 1, 0, 0, 0, 0, 0, 1], // From digit 4
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // From digit 5
[1, 1, 0, 0, 0, 0, 0, 1, 0, 0], // From digit 6
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0], // From digit 7
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0], // From digit 8
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0] // From digit 9
];
// Compute matrix^(n-1)
const resultMatrix = matrixPower(matrix, n - 1, MOD);
// Calculate the final answer: sum of all elements in the result matrix
let result = 0;
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
result = (result + resultMatrix[i][j]) % MOD;
}
}
return result;
}
/**
* Compute the power of a matrix using binary exponentiation.
*
* @param {number[][]} matrix - The base matrix
* @param {number} n - The exponent
* @param {number} mod - The modulo value
* @return {number[][]} - The resulting matrix
*/
function matrixPower(matrix, n, mod) {
// Base case: matrix^0 = identity matrix
if (n === 0) {
const identity = Array(10).fill().map(() => Array(10).fill(0));
for (let i = 0; i < 10; i++) {
identity[i][i] = 1;
}
return identity;
}
// If n is odd, compute matrix^(n-1) * matrix
if (n % 2 === 1) {
const result = matrixPower(matrix, n - 1, mod);
return multiplyMatrices(result, matrix, mod);
}
// If n is even, compute (matrix^(n/2))^2
const half = matrixPower(matrix, Math.floor(n / 2), mod);
return multiplyMatrices(half, half, mod);
}
/**
* Multiply two matrices.
*
* @param {number[][]} a - First matrix
* @param {number[][]} b - Second matrix
* @param {number} mod - The modulo value
* @return {number[][]} - The product of the two matrices
*/
function multiplyMatrices(a, b, mod) {
const result = Array(10).fill().map(() => Array(10).fill(0));
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
for (let k = 0; k < 10; k++) {
result[i][j] = (result[i][j] + a[i][k] * b[k][j]) % mod;
}
}
}
return result;
}
// Test cases
console.log(knightDialer(1)); // 10
console.log(knightDialer(2)); // 20
console.log(knightDialer(3)); // 46
console.log(knightDialer(4)); // 104
console.log(knightDialer(3131)); // 136006598
console.log(knightDialerOptimized(1)); // 10
console.log(knightDialerOptimized(2)); // 20
console.log(knightDialerOptimized(3)); // 46
console.log(knightDialerOptimized(4)); // 104
console.log(knightDialerOptimized(3131)); // 136006598
console.log(knightDialerMatrix(1)); // 10
console.log(knightDialerMatrix(2)); // 20
console.log(knightDialerMatrix(3)); // 46
console.log(knightDialerMatrix(4)); // 104
console.log(knightDialerMatrix(3131)); // 136006598

Step-by-Step Explanation

Let's break down the implementation:

  1. Define Knight Moves: Define the possible knight moves for each digit on the phone keypad, considering the L-shaped movement pattern of a chess knight.
  2. Initialize DP Array: Set up a dynamic programming array to keep track of the number of distinct phone numbers of a certain length ending with each digit.
  3. Establish Base Cases: For a phone number of length 1, there is exactly one way to dial each digit (by simply pressing that digit).
  4. Fill DP Array: For each length and each digit, calculate the number of ways to reach that digit by considering all possible previous digits that can lead to it through a valid knight move.
  5. Calculate Final Answer: Sum up the number of ways to dial a phone number of the target length ending with each digit, applying the modulo operation to avoid integer overflow.
ProblemSolutionCode
101 Logo
onenoughtone