935. 骑士拨号器
骑士在一张 n x n 的棋盘上巡视。在一个有效骑士巡视中,骑士可以从一个数字单元格开始,然后执行 n - 1 次移动,每次移动都必须是标准的骑士移动:呈 “L” 形状,即向一个方向移动两个单元格,然后垂直移动一个单元格,或向一个方向移动一个单元格,然后垂直移动两个单元格。
骑士只能站在数字单元格上(即蓝色单元格)。
给定一个整数 n,返回我们可以拨出的不同电话号码的数量。
因为答案可能很大,所以输出答案模 10^9 + 7。
示例 1:
输入:n = 1 输出:10 解释:我们需要拨出一个长度为 1 的数字,所以可以拨出 0-9,共 10 个数字。
示例 2:
输入:n = 2 输出:20 解释:所有可能的数字序列是:[04, 06, 16, 18, 27, 29, 34, 38, 40, 43, 49, 60, 61, 67, 72, 76, 81, 83, 92, 94]
示例 3:
输入:n = 3131 输出:136006598 解释:注意输出应当为模 10^9 + 7 的结果。
提示:
- 1 <= n <= 5000
func knightDialer(n int) int {
}动态规划思路:
- 定义状态:dp[i][j] 表示第 i 步时,以数字 j 结尾的方案数
- 状态转移:对于每个数字 j,找到它可以由哪些数字转移而来
- 初始状态:dp[0][j] = 1 (对于所有可达的数字 j)
骑士的移动规则决定了每个数字可以跳到的位置:
- 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
func knightDialer(n int) int {
MOD := 1000000007
// 定义每个数字可以跳到的位置
jumps := [][]int{
{4, 6}, // 0
{6, 8}, // 1
{7, 9}, // 2
{4, 8}, // 3
{0, 3, 9}, // 4
{}, // 5 (无法跳到任何位置)
{0, 1, 7}, // 6
{2, 6}, // 7
{1, 3}, // 8
{2, 4}, // 9
}
// dp[i][j] 表示第 i 步时,以数字 j 结尾的方案数
prev := make([]int, 10)
for i := 0; i < 10; i++ {
prev[i] = 1
}
for step := 1; step < n; step++ {
curr := make([]int, 10)
for j := 0; j < 10; j++ {
for _, next := range jumps[j] {
curr[next] = (curr[next] + prev[j]) % MOD
}
}
prev = curr
}
result := 0
for i := 0; i < 10; i++ {
result = (result + prev[i]) % MOD
}
return result
}
loommii