问题描述
小F正在使用一个骑士跳跃方式的拨号器。这个拨号器是一个类似电话键盘的 3x4 矩阵,每个数字对应一个单元格,骑士只能站在蓝色数字单元格上进行跳跃(数字 1 到 9 和 0)。骑士的移动方式和国际象棋中的马相同:它可以垂直移动两个单元格并水平移动一个单元格,或水平移动两个单元格并垂直移动一个单元格,形成 "L" 形。## 拨号器
问题理解
我们需要计算骑士在 n 次跳跃后可以形成的不同电话号码的数量。骑士的跳跃方式类似于国际象棋中的马,即它可以垂直移动两个单元格并水平移动一个单元格,或水平移动两个单元格并垂直移动一个单元格,形成 "L" 形。
数据结构的选择逻辑
-
跳跃规则:
- 我们使用一个字典
jumps来存储每个数字可以跳到的下一个数字。例如,数字1可以跳到数字6和8。
- 我们使用一个字典
-
动态规划数组:
- 我们使用一个二维数组
dp,其中dp[i][j]表示在i次跳跃后,骑士在数字j上可以形成的不同电话号码的数量。
- 我们使用一个二维数组
算法步骤
-
初始化:
- 当
i = 0时,dp[0][j] = 1,因为骑士可以从任何一个数字开始,且不需要跳跃。
- 当
-
状态转移:
- 对于每个数字
j,我们可以根据骑士的跳跃规则,计算出它可以跳到的下一个数字。 - 例如,如果骑士当前在数字
1,它可以跳到数字6和8。 - 因此,
dp[i+1][next_number] += dp[i][j],其中next_number是骑士从j可以跳到的数字。
- 对于每个数字
-
最终结果:
- 最终的结果是
dp[n-1][j]的总和,其中j是所有可能的数字。 def solution(n: int) -> int: MOD = 10**9 + 7
定义骑士可以跳跃的规则
jumps = { 1: [6, 8], 2: [7, 9], 3: [4, 8], 4: [3, 9, 0], 5: [], # 5 不能跳到任何其他数字 6: [1, 7, 0], 7: [2, 6], 8: [1, 3], 9: [2, 4], 0: [4, 6] }
初始化 dp 数组
dp = [[0] * 10 for _ in range(n)]
初始化第一行
for i in range(10): dp[0][i] = 1
填充 dp 数组
for i in range(1, n): for j in range(10): for next_number in jumps[j]: dp[i][next_number] = (dp[i][next_number] + dp[i-1][j]) % MOD
计算最终结果
result = sum(dp[n-1]) % MOD
return result
- 最终的结果是
if name == 'main': print(solution(1) == 10) print(solution(2) == 20) print(solution(3) == 46) print(solution(4) == 104)