diff --git a/solution/0900-0999/0935.Knight Dialer/README.md b/solution/0900-0999/0935.Knight Dialer/README.md index 25f26a97b5fa6..ce8586e01111f 100644 --- a/solution/0900-0999/0935.Knight Dialer/README.md +++ b/solution/0900-0999/0935.Knight Dialer/README.md @@ -77,6 +77,43 @@ tags: ### 方法一:递推 +根据题目描述,我们需要计算出长度为 $n$ 的不同电话号码的数量。其中,每个数字的上一个数字只有固定的几个,我们可以列出每个数字的上一个数字: + +| 当前数字 | 上一个数字 | +| -------- | ---------- | +| 0 | 4, 6 | +| 1 | 6, 8 | +| 2 | 7, 9 | +| 3 | 4, 8 | +| 4 | 0, 3, 9 | +| 5 | | +| 6 | 0, 1, 7 | +| 7 | 2, 6 | +| 8 | 1, 3 | +| 9 | 2, 4 | + +我们可以通过递推的方式,计算出长度为 $n$ 的不同电话号码的数量。设 $f[i]$ 表示长度为 $i$ 的不同电话号码的数量,初始时 $f[1] = 1$。对于长度为 $i$ 的电话号码,我们可以通过长度为 $i - 1$ 的电话号码计算出来,因此我们可以得到递推关系: + +$$ +\begin{aligned} +g[0] & = f[4] + f[6] \\ +g[1] & = f[6] + f[8] \\ +g[2] & = f[7] + f[9] \\ +g[3] & = f[4] + f[8] \\ +g[4] & = f[0] + f[3] + f[9] \\ +g[6] & = f[0] + f[1] + f[7] \\ +g[7] & = f[2] + f[6] \\ +g[8] & = f[1] + f[3] \\ +g[9] & = f[2] + f[4] +\end{aligned} +$$ + +然后,我们将 $f$ 更新为 $g$,继续计算下一个长度的电话号码,直到计算出长度为 $n$ 的电话号码的数量。 + +最后,我们将 $f$ 中所有元素相加,取模 $10^9 + 7$,即为答案。 + +时间复杂度 $O(n)$,其中 $n$ 为电话号码的长度。空间复杂度 $O(|\Sigma|)$,其中 $\Sigma$ 为数字集合,本题中 $|\Sigma| = 10$。 + #### Python3 @@ -84,56 +121,44 @@ tags: ```python class Solution: def knightDialer(self, n: int) -> int: - if n == 1: - return 10 f = [1] * 10 for _ in range(n - 1): - t = [0] * 10 - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - f = t - return sum(t) % (10**9 + 7) + g = [0] * 10 + g[0] = f[4] + f[6] + g[1] = f[6] + f[8] + g[2] = f[7] + f[9] + g[3] = f[4] + f[8] + g[4] = f[0] + f[3] + f[9] + g[6] = f[0] + f[1] + f[7] + g[7] = f[2] + f[6] + g[8] = f[1] + f[3] + g[9] = f[2] + f[4] + f = g + return sum(f) % (10**9 + 7) ``` #### Java ```java class Solution { - private static final int MOD = (int) 1e9 + 7; - public int knightDialer(int n) { - if (n == 1) { - return 10; - } + final int mod = (int) 1e9 + 7; long[] f = new long[10]; Arrays.fill(f, 1); while (--n > 0) { - long[] t = new long[10]; - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; - } + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - long ans = 0; - for (long v : f) { - ans = (ans + v) % MOD; - } - return (int) ans; + return (int) (Arrays.stream(f).sum() % mod); } } ``` @@ -141,29 +166,25 @@ class Solution { #### C++ ```cpp -using ll = long long; - class Solution { public: int knightDialer(int n) { - if (n == 1) return 10; - int mod = 1e9 + 7; - vector f(10, 1ll); + const int mod = 1e9 + 7; + vector f(10, 1); while (--n) { - vector t(10); - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) f[i] = t[i] % mod; + vector g(10); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - ll ans = accumulate(f.begin(), f.end(), 0ll); - return (int) (ans % mod); + return accumulate(f.begin(), f.end(), 0LL) % mod; } }; ``` @@ -171,35 +192,29 @@ public: #### Go ```go -func knightDialer(n int) int { - if n == 1 { - return 10 - } +func knightDialer(n int) (ans int) { f := make([]int, 10) for i := range f { f[i] = 1 } - mod := int(1e9) + 7 + const mod int = 1e9 + 7 for i := 1; i < n; i++ { - t := make([]int, 10) - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - for j, v := range t { - f[j] = v % mod - } + g := make([]int, 10) + g[0] = (f[4] + f[6]) % mod + g[1] = (f[6] + f[8]) % mod + g[2] = (f[7] + f[9]) % mod + g[3] = (f[4] + f[8]) % mod + g[4] = (f[0] + f[3] + f[9]) % mod + g[6] = (f[0] + f[1] + f[7]) % mod + g[7] = (f[2] + f[6]) % mod + g[8] = (f[1] + f[3]) % mod + g[9] = (f[2] + f[4]) % mod + f = g } - ans := 0 - for _, v := range f { - ans = (ans + v) % mod + for _, x := range f { + ans = (ans + x) % mod } - return ans + return } ``` @@ -207,67 +222,363 @@ func knightDialer(n int) int { ```ts function knightDialer(n: number): number { - const MOD: number = 1e9 + 7; + const mod = 1e9 + 7; + const f: number[] = Array(10).fill(1); + while (--n) { + const g: number[] = Array(10).fill(0); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f.splice(0, 10, ...g); + } + return f.reduce((a, b) => (a + b) % mod); +} +``` - if (n === 1) { - return 10; +#### C# + +```cs +public class Solution { + public int KnightDialer(int n) { + const int mod = 1000000007; + long[] f = new long[10]; + for (int i = 0; i < 10; i++) { + f[i] = 1; + } + + while (--n > 0) { + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; + } + + return (int)(f.Sum() % mod); } +} +``` + + - const f: number[] = new Array(10).fill(1); + + + + +### 方法二:矩阵快速幂加速递推 + +我们假设 $T(n)$ 表示一个 $1 \times 10$ 的矩阵 $\begin{bmatrix} F_0 & F_1 & F_2 \cdots F_9 \end{bmatrix}$,其中 $F_i$ 表示第 $i$ 个电话号码的数量。我们希望根据 $T(n - 1)$ 推出 $T(n)$。也即是说,我们需要一个矩阵 $\textit{base}$,使得 $T(n - 1) \times \textit{base} = T(n)$,即: + +$$ +\begin{bmatrix} +F_0 & F_1 & F_2 \cdots F_9 +\end{bmatrix} \times \textit{base} = \begin{bmatrix} F_0' & F_1' & F_2' \cdots F_9' \end{bmatrix} +$$ + +由于 $F_i' = \sum_{j} F_j$,其中 $j$ 是 $i$ 的上一个数字,所以矩阵 $\textit{base}$ 的第 $1$ 列为: + +$$ +\begin{bmatrix} +0 \\ +0 \\ +0 \\ +0 \\ +1 \\ +0 \\ +1 \\ +0 \\ +0 \\ +0 +\end{bmatrix} +$$ + +依次类推,我们可以得到矩阵 $\textit{base}$ 如下: + +$$ +\begin{bmatrix} +0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 \\ +0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ +0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 \\ +0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 \\ +1 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 \\ +0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ +1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ +0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ +0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ +0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 +\end{bmatrix} +$$ + +我们定义初始矩阵 $res = \begin{bmatrix} 1 & 1 & 1 \cdots 1 \end{bmatrix}$,与 $n - 1$ 个 $\textit{base}$ 矩阵相乘,即可得到 $T(n)$。最后,我们将 $T(n)$ 中所有元素相加,取模 $10^9 + 7$,即为答案。求 $\textit{base}^{n - 1}$,可以通过矩阵快速幂的方式,时间复杂度为 $O(\log n)$。 + +时间复杂度 $O(\log n)$,空间复杂度 $O(|\Sigma|^2)$,其中 $\Sigma$ 为数字集合,本题中 $|\Sigma| = 10$。 - while (--n > 0) { - const t: number[] = new Array(10).fill(0); + + +#### Python3 - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; +```python +import numpy as np + +base = [ + (0, 0, 0, 0, 1, 0, 1, 0, 0, 0), + (0, 0, 0, 0, 0, 0, 1, 0, 1, 0), + (0, 0, 0, 0, 0, 0, 0, 1, 0, 1), + (0, 0, 0, 0, 1, 0, 0, 0, 1, 0), + (1, 0, 0, 1, 0, 0, 0, 0, 0, 1), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (1, 1, 0, 0, 0, 0, 0, 1, 0, 0), + (0, 0, 1, 0, 0, 0, 1, 0, 0, 0), + (0, 1, 0, 1, 0, 0, 0, 0, 0, 0), + (0, 0, 1, 0, 1, 0, 0, 0, 0, 0), +] + + +class Solution: + def knightDialer(self, n: int) -> int: + factor = np.asmatrix(base, np.dtype("O")) + res = np.asmatrix([[1] * 10], np.dtype("O")) + n -= 1 + mod = 10**9 + 7 + while n: + if n & 1: + res = res * factor % mod + factor = factor * factor % mod + n >>= 1 + return res.sum() % mod +``` + +#### Java - for (let i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; +```java +class Solution { + private final int mod = (int) 1e9 + 7; + private final int[][] base = {{0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + + public int knightDialer(int n) { + int[][] res = pow(base, n - 1); + int ans = 0; + for (int x : res[0]) { + ans = (ans + x) % mod; } + return ans; } - let ans: number = 0; - for (const v of f) { - ans = (ans + v) % MOD; + private int[][] mul(int[][] a, int[][] b) { + int m = a.length, n = b[0].length; + int[][] c = new int[m][n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.length; ++k) { + c[i][j] = (int) ((c[i][j] + 1L * a[i][k] * b[k][j] % mod) % mod); + } + } + } + return c; } - return ans; + private int[][] pow(int[][] a, int n) { + int[][] res = new int[1][a.length]; + Arrays.fill(res[0], 1); + while (n > 0) { + if ((n & 1) == 1) { + res = mul(res, a); + } + a = mul(a, a); + n >>= 1; + } + return res; + } } ``` -#### C# +#### C++ -```cs -public class Solution { - public int KnightDialer(int n) { - if (n == 1) return 10; - int A = 4; - int B = 2; - int C = 2; - int D = 1; - int MOD = (int)1e9 + 7; - for (int i = 0; i < n - 1; i++) { - int tempA = A; - int tempB = B; - int tempC = C; - int tempD = D; - A = ((2 * tempB) % MOD + (2 * tempC) % MOD) % MOD; - B = tempA; - C = (tempA + (2 * tempD) % MOD) % MOD; - D = tempC; +```cpp +class Solution { +public: + int knightDialer(int n) { + const int mod = 1e9 + 7; + vector> base = { + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + vector> res = pow(base, n - 1, mod); + return accumulate(res[0].begin(), res[0].end(), 0LL) % mod; + } + +private: + vector> mul(const vector>& a, const vector>& b, int mod) { + int m = a.size(), n = b[0].size(); + vector> c(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.size(); ++k) { + c[i][j] = (c[i][j] + (1LL * a[i][k] * b[k][j]) % mod) % mod; + } + } + } + return c; + } + + vector> pow(vector>& a, int n, int mod) { + int size = a.size(); + vector> res(1, vector(size, 1)); + while (n > 0) { + if (n % 2 == 1) { + res = mul(res, a, mod); + } + a = mul(a, a, mod); + n /= 2; + } + return res; + } +}; +``` + +#### Go + +```go +const mod = 1e9 + 7 + +func knightDialer(n int) int { + base := [][]int{ + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + } + + res := pow(base, n-1) + ans := 0 + for _, x := range res[0] { + ans = (ans + x) % mod + } + return ans +} + +func mul(a, b [][]int) [][]int { + m := len(a) + n := len(b[0]) + c := make([][]int, m) + for i := range c { + c[i] = make([]int, n) + } + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + for k := 0; k < len(b); k++ { + c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % mod + } + } + } + return c +} + +func pow(a [][]int, n int) [][]int { + size := len(a) + res := make([][]int, 1) + res[0] = make([]int, size) + for i := 0; i < size; i++ { + res[0][i] = 1 + } + + for n > 0 { + if n%2 == 1 { + res = mul(res, a) + } + a = mul(a, a) + n /= 2 + } + + return res +} +``` + +#### TypeScript + +```ts +const mod = 1e9 + 7; + +function knightDialer(n: number): number { + const base: number[][] = [ + [0, 0, 0, 0, 1, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 1, 0], + [1, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 1, 0, 0, 0], + [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 0, 0, 0, 0], + ]; + + const res = pow(base, n - 1); + let ans = 0; + for (const x of res[0]) { + ans = (ans + x) % mod; + } + return ans; +} + +function mul(a: number[][], b: number[][]): number[][] { + const m = a.length; + const n = b[0].length; + const c: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + for (let k = 0; k < b.length; k++) { + c[i][j] = + (c[i][j] + Number((BigInt(a[i][k]) * BigInt(b[k][j])) % BigInt(mod))) % mod; + } } + } + return c; +} - int ans = (A + B) % MOD; - ans = (ans + C) % MOD; - return (ans + D) % MOD; +function pow(a: number[][], n: number): number[][] { + const size = a.length; + let res: number[][] = Array.from({ length: 1 }, () => Array(size).fill(1)); + + while (n > 0) { + if (n % 2 === 1) { + res = mul(res, a); + } + a = mul(a, a); + n = Math.floor(n / 2); } + + return res; } ``` diff --git a/solution/0900-0999/0935.Knight Dialer/README_EN.md b/solution/0900-0999/0935.Knight Dialer/README_EN.md index 68d6862f666a8..8f58010ff7b9e 100644 --- a/solution/0900-0999/0935.Knight Dialer/README_EN.md +++ b/solution/0900-0999/0935.Knight Dialer/README_EN.md @@ -66,7 +66,44 @@ tags: -### Solution 1 +### Solution 1: Recurrence + +According to the problem description, we need to calculate the number of different phone numbers of length $n$. Each digit can only follow certain fixed digits, which we can list as follows: + +| Current Digit | Previous Digits | +| ------------- | --------------- | +| 0 | 4, 6 | +| 1 | 6, 8 | +| 2 | 7, 9 | +| 3 | 4, 8 | +| 4 | 0, 3, 9 | +| 5 | | +| 6 | 0, 1, 7 | +| 7 | 2, 6 | +| 8 | 1, 3 | +| 9 | 2, 4 | + +We can use a recurrence approach to calculate the number of different phone numbers of length $n$. Let $f[i]$ represent the number of different phone numbers of length $i$. Initially, $f[1] = 1$. For phone numbers of length $i$, we can calculate them based on phone numbers of length $i - 1$. Therefore, we can derive the recurrence relations: + +$$ +\begin{aligned} +g[0] & = f[4] + f[6] \\ +g[1] & = f[6] + f[8] \\ +g[2] & = f[7] + f[9] \\ +g[3] & = f[4] + f[8] \\ +g[4] & = f[0] + f[3] + f[9] \\ +g[6] & = f[0] + f[1] + f[7] \\ +g[7] & = f[2] + f[6] \\ +g[8] & = f[1] + f[3] \\ +g[9] & = f[2] + f[4] +\end{aligned} +$$ + +Then, we update $f$ to $g$ and continue calculating the phone numbers of the next length until we calculate the number of phone numbers of length $n$. + +Finally, we sum all the elements in $f$ and take the result modulo $10^9 + 7$ to get the answer. + +The time complexity is $O(n)$, where $n$ is the length of the phone number. The space complexity is $O(|\Sigma|)$, where $\Sigma$ is the set of digits, and in this problem $|\Sigma| = 10$. @@ -75,56 +112,44 @@ tags: ```python class Solution: def knightDialer(self, n: int) -> int: - if n == 1: - return 10 f = [1] * 10 for _ in range(n - 1): - t = [0] * 10 - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - f = t - return sum(t) % (10**9 + 7) + g = [0] * 10 + g[0] = f[4] + f[6] + g[1] = f[6] + f[8] + g[2] = f[7] + f[9] + g[3] = f[4] + f[8] + g[4] = f[0] + f[3] + f[9] + g[6] = f[0] + f[1] + f[7] + g[7] = f[2] + f[6] + g[8] = f[1] + f[3] + g[9] = f[2] + f[4] + f = g + return sum(f) % (10**9 + 7) ``` #### Java ```java class Solution { - private static final int MOD = (int) 1e9 + 7; - public int knightDialer(int n) { - if (n == 1) { - return 10; - } + final int mod = (int) 1e9 + 7; long[] f = new long[10]; Arrays.fill(f, 1); while (--n > 0) { - long[] t = new long[10]; - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; - } + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - long ans = 0; - for (long v : f) { - ans = (ans + v) % MOD; - } - return (int) ans; + return (int) (Arrays.stream(f).sum() % mod); } } ``` @@ -132,29 +157,25 @@ class Solution { #### C++ ```cpp -using ll = long long; - class Solution { public: int knightDialer(int n) { - if (n == 1) return 10; - int mod = 1e9 + 7; - vector f(10, 1ll); + const int mod = 1e9 + 7; + vector f(10, 1); while (--n) { - vector t(10); - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) f[i] = t[i] % mod; + vector g(10); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - ll ans = accumulate(f.begin(), f.end(), 0ll); - return (int) (ans % mod); + return accumulate(f.begin(), f.end(), 0LL) % mod; } }; ``` @@ -162,35 +183,29 @@ public: #### Go ```go -func knightDialer(n int) int { - if n == 1 { - return 10 - } +func knightDialer(n int) (ans int) { f := make([]int, 10) for i := range f { f[i] = 1 } - mod := int(1e9) + 7 + const mod int = 1e9 + 7 for i := 1; i < n; i++ { - t := make([]int, 10) - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - for j, v := range t { - f[j] = v % mod - } + g := make([]int, 10) + g[0] = (f[4] + f[6]) % mod + g[1] = (f[6] + f[8]) % mod + g[2] = (f[7] + f[9]) % mod + g[3] = (f[4] + f[8]) % mod + g[4] = (f[0] + f[3] + f[9]) % mod + g[6] = (f[0] + f[1] + f[7]) % mod + g[7] = (f[2] + f[6]) % mod + g[8] = (f[1] + f[3]) % mod + g[9] = (f[2] + f[4]) % mod + f = g } - ans := 0 - for _, v := range f { - ans = (ans + v) % mod + for _, x := range f { + ans = (ans + x) % mod } - return ans + return } ``` @@ -198,66 +213,427 @@ func knightDialer(n int) int { ```ts function knightDialer(n: number): number { - const MOD: number = 1e9 + 7; + const mod = 1e9 + 7; + const f: number[] = Array(10).fill(1); + while (--n) { + const g: number[] = Array(10).fill(0); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f.splice(0, 10, ...g); + } + return f.reduce((a, b) => (a + b) % mod); +} +``` - if (n === 1) { - return 10; +#### C# + +```cs +public class Solution { + public int KnightDialer(int n) { + const int mod = 1000000007; + long[] f = new long[10]; + for (int i = 0; i < 10; i++) { + f[i] = 1; + } + + while (--n > 0) { + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; + } + + return (int)(f.Sum() % mod); } +} +``` + + + + - const f: number[] = new Array(10).fill(1); + - while (--n > 0) { - const t: number[] = new Array(10).fill(0); +### Solution 2: Matrix Exponentiation to Accelerate Recurrence + +Let's denote $T(n)$ as a $1 \times 10$ matrix $\begin{bmatrix} F_0 & F_1 & F_2 \cdots F_9 \end{bmatrix}$, where $F_i$ represents the number of phone numbers ending with digit $i$. We want to derive $T(n)$ from $T(n - 1)$. In other words, we need a matrix $\textit{base}$ such that $T(n - 1) \times \textit{base} = T(n)$, i.e.: + +$$ +\begin{bmatrix} +F_0 & F_1 & F_2 \cdots F_9 +\end{bmatrix} \times \textit{base} = \begin{bmatrix} F_0' & F_1' & F_2' \cdots F_9' \end{bmatrix} +$$ + +Since $F_i' = \sum_{j} F_j$, where $j$ is the previous digit of $i$, the first column of the matrix $\textit{base}$ is: + +$$ +\begin{bmatrix} +0 \\ +0 \\ +0 \\ +0 \\ +1 \\ +0 \\ +1 \\ +0 \\ +0 \\ +0 +\end{bmatrix} +$$ + +Similarly, we can derive the entire matrix $\textit{base}$ as follows: + +$$ +\begin{bmatrix} +0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 \\ +0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ +0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 \\ +0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 \\ +1 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 1 \\ +0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ +1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ +0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ +0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ +0 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 +\end{bmatrix} +$$ + +We define the initial matrix $res = \begin{bmatrix} 1 & 1 & 1 \cdots 1 \end{bmatrix}$, and multiply it by the matrix $\textit{base}$ raised to the power of $n - 1$ to obtain $T(n)$. Finally, we sum all elements in $T(n)$ and take the result modulo $10^9 + 7$ to get the answer. The matrix $\textit{base}^{n - 1}$ can be computed using matrix exponentiation, which has a time complexity of $O(\log n)$. + +The time complexity is $O(\log n)$, and the space complexity is $O(|\Sigma|^2)$, where $\Sigma$ is the set of digits, and in this problem $|\Sigma| = 10$. - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; + - for (let i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; +#### Python3 + +```python +import numpy as np + +base = [ + (0, 0, 0, 0, 1, 0, 1, 0, 0, 0), + (0, 0, 0, 0, 0, 0, 1, 0, 1, 0), + (0, 0, 0, 0, 0, 0, 0, 1, 0, 1), + (0, 0, 0, 0, 1, 0, 0, 0, 1, 0), + (1, 0, 0, 1, 0, 0, 0, 0, 0, 1), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (1, 1, 0, 0, 0, 0, 0, 1, 0, 0), + (0, 0, 1, 0, 0, 0, 1, 0, 0, 0), + (0, 1, 0, 1, 0, 0, 0, 0, 0, 0), + (0, 0, 1, 0, 1, 0, 0, 0, 0, 0), +] + + +class Solution: + def knightDialer(self, n: int) -> int: + factor = np.asmatrix(base, np.dtype("O")) + res = np.asmatrix([[1] * 10], np.dtype("O")) + n -= 1 + mod = 10**9 + 7 + while n: + if n & 1: + res = res * factor % mod + factor = factor * factor % mod + n >>= 1 + return res.sum() % mod +``` + +#### Java + +```java +class Solution { + private final int mod = (int) 1e9 + 7; + private final int[][] base = {{0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + + public int knightDialer(int n) { + int[][] res = pow(base, n - 1); + int ans = 0; + for (int x : res[0]) { + ans = (ans + x) % mod; + } + return ans; + } + + private int[][] mul(int[][] a, int[][] b) { + int m = a.length, n = b[0].length; + int[][] c = new int[m][n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.length; ++k) { + c[i][j] = (int) ((c[i][j] + 1L * a[i][k] * b[k][j] % mod) % mod); + } + } + } + return c; + } + + private int[][] pow(int[][] a, int n) { + int[][] res = new int[1][a.length]; + Arrays.fill(res[0], 1); + while (n > 0) { + if ((n & 1) == 1) { + res = mul(res, a); + } + a = mul(a, a); + n >>= 1; } + return res; } +} +``` - let ans: number = 0; - for (const v of f) { - ans = (ans + v) % MOD; +#### C++ + +```cpp +class Solution { +public: + int knightDialer(int n) { + const int mod = 1e9 + 7; + vector> base = { + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + vector> res = pow(base, n - 1, mod); + return accumulate(res[0].begin(), res[0].end(), 0LL) % mod; } +private: + vector> mul(const vector>& a, const vector>& b, int mod) { + int m = a.size(), n = b[0].size(); + vector> c(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.size(); ++k) { + c[i][j] = (c[i][j] + (1LL * a[i][k] * b[k][j]) % mod) % mod; + } + } + } + return c; + } + + vector> pow(vector>& a, int n, int mod) { + int size = a.size(); + vector> res(1, vector(size, 1)); + while (n > 0) { + if (n % 2 == 1) { + res = mul(res, a, mod); + } + a = mul(a, a, mod); + n /= 2; + } + return res; + } +}; +``` + +#### Go + +```go +const mod = 1e9 + 7 + +func knightDialer(n int) int { + base := [][]int{ + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + } + + res := pow(base, n-1) + ans := 0 + for _, x := range res[0] { + ans = (ans + x) % mod + } + return ans +} + +func mul(a, b [][]int) [][]int { + m := len(a) + n := len(b[0]) + c := make([][]int, m) + for i := range c { + c[i] = make([]int, n) + } + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + for k := 0; k < len(b); k++ { + c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % mod + } + } + } + return c +} + +func pow(a [][]int, n int) [][]int { + size := len(a) + res := make([][]int, 1) + res[0] = make([]int, size) + for i := 0; i < size; i++ { + res[0][i] = 1 + } + + for n > 0 { + if n%2 == 1 { + res = mul(res, a) + } + a = mul(a, a) + n /= 2 + } + + return res +} +``` + +#### TypeScript + +```ts +const mod = 1e9 + 7; + +function knightDialer(n: number): number { + const base: number[][] = [ + [0, 0, 0, 0, 1, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 1, 0], + [1, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 1, 0, 0, 0], + [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 0, 0, 0, 0], + ]; + + const res = pow(base, n - 1); + let ans = 0; + for (const x of res[0]) { + ans = (ans + x) % mod; + } return ans; } + +function mul(a: number[][], b: number[][]): number[][] { + const m = a.length; + const n = b[0].length; + const c: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + for (let k = 0; k < b.length; k++) { + c[i][j] = + (c[i][j] + Number((BigInt(a[i][k]) * BigInt(b[k][j])) % BigInt(mod))) % mod; + } + } + } + return c; +} + +function pow(a: number[][], n: number): number[][] { + const size = a.length; + let res: number[][] = Array.from({ length: 1 }, () => Array(size).fill(1)); + + while (n > 0) { + if (n % 2 === 1) { + res = mul(res, a); + } + a = mul(a, a); + n = Math.floor(n / 2); + } + + return res; +} ``` #### C# ```cs public class Solution { + private const int mod = 1000000007; + private readonly int[][] baseMatrix = { + new int[] {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + new int[] {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + new int[] {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + new int[] {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + new int[] {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + new int[] {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + new int[] {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + new int[] {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + new int[] {0, 0, 1, 0, 1, 0, 0, 0, 0, 0} + }; + public int KnightDialer(int n) { - if (n == 1) return 10; - int A = 4; - int B = 2; - int C = 2; - int D = 1; - int MOD = (int)1e9 + 7; - for (int i = 0; i < n - 1; i++) { - int tempA = A; - int tempB = B; - int tempC = C; - int tempD = D; - A = ((2 * tempB) % MOD + (2 * tempC) % MOD) % MOD; - B = tempA; - C = (tempA + (2 * tempD) % MOD) % MOD; - D = tempC; + int[][] res = Pow(baseMatrix, n - 1); + int ans = 0; + foreach (var x in res[0]) { + ans = (ans + x) % mod; + } + return ans; + } + + private int[][] Mul(int[][] a, int[][] b) { + int m = a.Length, n = b[0].Length; + int[][] c = new int[m][]; + for (int i = 0; i < m; i++) { + c[i] = new int[n]; + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + for (int k = 0; k < b.Length; k++) { + c[i][j] = (int)((c[i][j] + (long)a[i][k] * b[k][j]) % mod); + } + } + } + return c; + } + + private int[][] Pow(int[][] a, int n) { + int size = a.Length; + int[][] res = new int[1][]; + res[0] = new int[size]; + for (int i = 0; i < size; i++) { + res[0][i] = 1; + } + + while (n > 0) { + if (n % 2 == 1) { + res = Mul(res, a); + } + a = Mul(a, a); + n /= 2; } - int ans = (A + B) % MOD; - ans = (ans + C) % MOD; - return (ans + D) % MOD; + return res; } } ``` diff --git a/solution/0900-0999/0935.Knight Dialer/Solution.cpp b/solution/0900-0999/0935.Knight Dialer/Solution.cpp index 5524fcf6d324f..89c955137edbb 100644 --- a/solution/0900-0999/0935.Knight Dialer/Solution.cpp +++ b/solution/0900-0999/0935.Knight Dialer/Solution.cpp @@ -1,25 +1,21 @@ -using ll = long long; - class Solution { public: int knightDialer(int n) { - if (n == 1) return 10; - int mod = 1e9 + 7; - vector f(10, 1ll); + const int mod = 1e9 + 7; + vector f(10, 1); while (--n) { - vector t(10); - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) f[i] = t[i] % mod; + vector g(10); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - ll ans = accumulate(f.begin(), f.end(), 0ll); - return (int) (ans % mod); + return accumulate(f.begin(), f.end(), 0LL) % mod; } -}; \ No newline at end of file +}; diff --git a/solution/0900-0999/0935.Knight Dialer/Solution.cs b/solution/0900-0999/0935.Knight Dialer/Solution.cs index 4c11a2da4ea9a..176163e623e16 100644 --- a/solution/0900-0999/0935.Knight Dialer/Solution.cs +++ b/solution/0900-0999/0935.Knight Dialer/Solution.cs @@ -1,24 +1,25 @@ public class Solution { public int KnightDialer(int n) { - if (n == 1) return 10; - int A = 4; - int B = 2; - int C = 2; - int D = 1; - int MOD = (int)1e9 + 7; - for (int i = 0; i < n - 1; i++) { - int tempA = A; - int tempB = B; - int tempC = C; - int tempD = D; - A = ((2 * tempB) % MOD + (2 * tempC) % MOD) % MOD; - B = tempA; - C = (tempA + (2 * tempD) % MOD) % MOD; - D = tempC; + const int mod = 1000000007; + long[] f = new long[10]; + for (int i = 0; i < 10; i++) { + f[i] = 1; } - int ans = (A + B) % MOD; - ans = (ans + C) % MOD; - return (ans + D) % MOD; + while (--n > 0) { + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; + } + + return (int)(f.Sum() % mod); } } diff --git a/solution/0900-0999/0935.Knight Dialer/Solution.go b/solution/0900-0999/0935.Knight Dialer/Solution.go index b79431dd881d4..732eb639d1fdb 100644 --- a/solution/0900-0999/0935.Knight Dialer/Solution.go +++ b/solution/0900-0999/0935.Knight Dialer/Solution.go @@ -1,30 +1,24 @@ -func knightDialer(n int) int { - if n == 1 { - return 10 - } +func knightDialer(n int) (ans int) { f := make([]int, 10) for i := range f { f[i] = 1 } - mod := int(1e9) + 7 + const mod int = 1e9 + 7 for i := 1; i < n; i++ { - t := make([]int, 10) - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - for j, v := range t { - f[j] = v % mod - } + g := make([]int, 10) + g[0] = (f[4] + f[6]) % mod + g[1] = (f[6] + f[8]) % mod + g[2] = (f[7] + f[9]) % mod + g[3] = (f[4] + f[8]) % mod + g[4] = (f[0] + f[3] + f[9]) % mod + g[6] = (f[0] + f[1] + f[7]) % mod + g[7] = (f[2] + f[6]) % mod + g[8] = (f[1] + f[3]) % mod + g[9] = (f[2] + f[4]) % mod + f = g } - ans := 0 - for _, v := range f { - ans = (ans + v) % mod + for _, x := range f { + ans = (ans + x) % mod } - return ans -} \ No newline at end of file + return +} diff --git a/solution/0900-0999/0935.Knight Dialer/Solution.java b/solution/0900-0999/0935.Knight Dialer/Solution.java index 6754bb1006ce8..f7c0fd12ea3c7 100644 --- a/solution/0900-0999/0935.Knight Dialer/Solution.java +++ b/solution/0900-0999/0935.Knight Dialer/Solution.java @@ -1,31 +1,21 @@ class Solution { - private static final int MOD = (int) 1e9 + 7; - public int knightDialer(int n) { - if (n == 1) { - return 10; - } + final int mod = (int) 1e9 + 7; long[] f = new long[10]; Arrays.fill(f, 1); while (--n > 0) { - long[] t = new long[10]; - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - for (int i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; - } - } - long ans = 0; - for (long v : f) { - ans = (ans + v) % MOD; + long[] g = new long[10]; + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f = g; } - return (int) ans; + return (int) (Arrays.stream(f).sum() % mod); } -} \ No newline at end of file +} diff --git a/solution/0900-0999/0935.Knight Dialer/Solution.py b/solution/0900-0999/0935.Knight Dialer/Solution.py index 2adde7d0abf21..770e1b3eebe3c 100644 --- a/solution/0900-0999/0935.Knight Dialer/Solution.py +++ b/solution/0900-0999/0935.Knight Dialer/Solution.py @@ -1,18 +1,16 @@ class Solution: def knightDialer(self, n: int) -> int: - if n == 1: - return 10 f = [1] * 10 for _ in range(n - 1): - t = [0] * 10 - t[0] = f[4] + f[6] - t[1] = f[6] + f[8] - t[2] = f[7] + f[9] - t[3] = f[4] + f[8] - t[4] = f[0] + f[3] + f[9] - t[6] = f[0] + f[1] + f[7] - t[7] = f[2] + f[6] - t[8] = f[1] + f[3] - t[9] = f[2] + f[4] - f = t - return sum(t) % (10**9 + 7) + g = [0] * 10 + g[0] = f[4] + f[6] + g[1] = f[6] + f[8] + g[2] = f[7] + f[9] + g[3] = f[4] + f[8] + g[4] = f[0] + f[3] + f[9] + g[6] = f[0] + f[1] + f[7] + g[7] = f[2] + f[6] + g[8] = f[1] + f[3] + g[9] = f[2] + f[4] + f = g + return sum(f) % (10**9 + 7) diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.cpp b/solution/0900-0999/0935.Knight Dialer/Solution2.cpp new file mode 100644 index 0000000000000..e47aeff26ec5c --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.cpp @@ -0,0 +1,46 @@ +class Solution { +public: + int knightDialer(int n) { + const int mod = 1e9 + 7; + vector> base = { + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + vector> res = pow(base, n - 1, mod); + return accumulate(res[0].begin(), res[0].end(), 0LL) % mod; + } + +private: + vector> mul(const vector>& a, const vector>& b, int mod) { + int m = a.size(), n = b[0].size(); + vector> c(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.size(); ++k) { + c[i][j] = (c[i][j] + (1LL * a[i][k] * b[k][j]) % mod) % mod; + } + } + } + return c; + } + + vector> pow(vector>& a, int n, int mod) { + int size = a.size(); + vector> res(1, vector(size, 1)); + while (n > 0) { + if (n % 2 == 1) { + res = mul(res, a, mod); + } + a = mul(a, a, mod); + n /= 2; + } + return res; + } +}; diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.cs b/solution/0900-0999/0935.Knight Dialer/Solution2.cs new file mode 100644 index 0000000000000..5144545e44300 --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.cs @@ -0,0 +1,60 @@ +public class Solution { + private const int mod = 1000000007; + private readonly int[][] baseMatrix = { + new int[] {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + new int[] {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + new int[] {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + new int[] {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + new int[] {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + new int[] {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + new int[] {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + new int[] {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + new int[] {0, 0, 1, 0, 1, 0, 0, 0, 0, 0} + }; + + public int KnightDialer(int n) { + int[][] res = Pow(baseMatrix, n - 1); + int ans = 0; + foreach (var x in res[0]) { + ans = (ans + x) % mod; + } + return ans; + } + + private int[][] Mul(int[][] a, int[][] b) { + int m = a.Length, n = b[0].Length; + int[][] c = new int[m][]; + for (int i = 0; i < m; i++) { + c[i] = new int[n]; + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + for (int k = 0; k < b.Length; k++) { + c[i][j] = (int)((c[i][j] + (long)a[i][k] * b[k][j]) % mod); + } + } + } + return c; + } + + private int[][] Pow(int[][] a, int n) { + int size = a.Length; + int[][] res = new int[1][]; + res[0] = new int[size]; + for (int i = 0; i < size; i++) { + res[0][i] = 1; + } + + while (n > 0) { + if (n % 2 == 1) { + res = Mul(res, a); + } + a = Mul(a, a); + n /= 2; + } + + return res; + } +} diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.go b/solution/0900-0999/0935.Knight Dialer/Solution2.go new file mode 100644 index 0000000000000..07b67e8b4f7d5 --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.go @@ -0,0 +1,59 @@ +const mod = 1e9 + 7 + +func knightDialer(n int) int { + base := [][]int{ + {0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, + } + + res := pow(base, n-1) + ans := 0 + for _, x := range res[0] { + ans = (ans + x) % mod + } + return ans +} + +func mul(a, b [][]int) [][]int { + m := len(a) + n := len(b[0]) + c := make([][]int, m) + for i := range c { + c[i] = make([]int, n) + } + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + for k := 0; k < len(b); k++ { + c[i][j] = (c[i][j] + a[i][k]*b[k][j]) % mod + } + } + } + return c +} + +func pow(a [][]int, n int) [][]int { + size := len(a) + res := make([][]int, 1) + res[0] = make([]int, size) + for i := 0; i < size; i++ { + res[0][i] = 1 + } + + for n > 0 { + if n%2 == 1 { + res = mul(res, a) + } + a = mul(a, a) + n /= 2 + } + + return res +} diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.java b/solution/0900-0999/0935.Knight Dialer/Solution2.java new file mode 100644 index 0000000000000..3c2285468478d --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.java @@ -0,0 +1,43 @@ +class Solution { + private final int mod = (int) 1e9 + 7; + private final int[][] base = {{0, 0, 0, 0, 1, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, {0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}; + + public int knightDialer(int n) { + int[][] res = pow(base, n - 1); + int ans = 0; + for (int x : res[0]) { + ans = (ans + x) % mod; + } + return ans; + } + + private int[][] mul(int[][] a, int[][] b) { + int m = a.length, n = b[0].length; + int[][] c = new int[m][n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < b.length; ++k) { + c[i][j] = (int) ((c[i][j] + 1L * a[i][k] * b[k][j] % mod) % mod); + } + } + } + return c; + } + + private int[][] pow(int[][] a, int n) { + int[][] res = new int[1][a.length]; + Arrays.fill(res[0], 1); + while (n > 0) { + if ((n & 1) == 1) { + res = mul(res, a); + } + a = mul(a, a); + n >>= 1; + } + return res; + } +} diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.py b/solution/0900-0999/0935.Knight Dialer/Solution2.py new file mode 100644 index 0000000000000..24e02ecbb1f34 --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.py @@ -0,0 +1,28 @@ +import numpy as np + +base = [ + (0, 0, 0, 0, 1, 0, 1, 0, 0, 0), + (0, 0, 0, 0, 0, 0, 1, 0, 1, 0), + (0, 0, 0, 0, 0, 0, 0, 1, 0, 1), + (0, 0, 0, 0, 1, 0, 0, 0, 1, 0), + (1, 0, 0, 1, 0, 0, 0, 0, 0, 1), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (1, 1, 0, 0, 0, 0, 0, 1, 0, 0), + (0, 0, 1, 0, 0, 0, 1, 0, 0, 0), + (0, 1, 0, 1, 0, 0, 0, 0, 0, 0), + (0, 0, 1, 0, 1, 0, 0, 0, 0, 0), +] + + +class Solution: + def knightDialer(self, n: int) -> int: + factor = np.asmatrix(base, np.dtype("O")) + res = np.asmatrix([[1] * 10], np.dtype("O")) + n -= 1 + mod = 10**9 + 7 + while n: + if n & 1: + res = res * factor % mod + factor = factor * factor % mod + n >>= 1 + return res.sum() % mod diff --git a/solution/0900-0999/0935.Knight Dialer/Solution2.ts b/solution/0900-0999/0935.Knight Dialer/Solution2.ts new file mode 100644 index 0000000000000..265a55c6ec1e0 --- /dev/null +++ b/solution/0900-0999/0935.Knight Dialer/Solution2.ts @@ -0,0 +1,54 @@ +const mod = 1e9 + 7; + +function knightDialer(n: number): number { + const base: number[][] = [ + [0, 0, 0, 0, 1, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 1, 0], + [1, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 1, 0, 0, 0], + [0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 0, 0, 0, 0], + ]; + + const res = pow(base, n - 1); + let ans = 0; + for (const x of res[0]) { + ans = (ans + x) % mod; + } + return ans; +} + +function mul(a: number[][], b: number[][]): number[][] { + const m = a.length; + const n = b[0].length; + const c: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + for (let k = 0; k < b.length; k++) { + c[i][j] = + (c[i][j] + Number((BigInt(a[i][k]) * BigInt(b[k][j])) % BigInt(mod))) % mod; + } + } + } + return c; +} + +function pow(a: number[][], n: number): number[][] { + const size = a.length; + let res: number[][] = Array.from({ length: 1 }, () => Array(size).fill(1)); + + while (n > 0) { + if (n % 2 === 1) { + res = mul(res, a); + } + a = mul(a, a); + n = Math.floor(n / 2); + } + + return res; +} diff --git a/solution/0900-0999/0935.Knight Dialer/solution.ts b/solution/0900-0999/0935.Knight Dialer/solution.ts index e262e04661c56..4695d9a4feddc 100644 --- a/solution/0900-0999/0935.Knight Dialer/solution.ts +++ b/solution/0900-0999/0935.Knight Dialer/solution.ts @@ -1,34 +1,18 @@ function knightDialer(n: number): number { - const MOD: number = 1e9 + 7; - - if (n === 1) { - return 10; + const mod = 1e9 + 7; + const f: number[] = Array(10).fill(1); + while (--n) { + const g: number[] = Array(10).fill(0); + g[0] = (f[4] + f[6]) % mod; + g[1] = (f[6] + f[8]) % mod; + g[2] = (f[7] + f[9]) % mod; + g[3] = (f[4] + f[8]) % mod; + g[4] = (f[0] + f[3] + f[9]) % mod; + g[6] = (f[0] + f[1] + f[7]) % mod; + g[7] = (f[2] + f[6]) % mod; + g[8] = (f[1] + f[3]) % mod; + g[9] = (f[2] + f[4]) % mod; + f.splice(0, 10, ...g); } - - const f: number[] = new Array(10).fill(1); - - while (--n > 0) { - const t: number[] = new Array(10).fill(0); - - t[0] = f[4] + f[6]; - t[1] = f[6] + f[8]; - t[2] = f[7] + f[9]; - t[3] = f[4] + f[8]; - t[4] = f[0] + f[3] + f[9]; - t[6] = f[0] + f[1] + f[7]; - t[7] = f[2] + f[6]; - t[8] = f[1] + f[3]; - t[9] = f[2] + f[4]; - - for (let i = 0; i < 10; ++i) { - f[i] = t[i] % MOD; - } - } - - let ans: number = 0; - for (const v of f) { - ans = (ans + v) % MOD; - } - - return ans; + return f.reduce((a, b) => (a + b) % mod); }