拨号器

191 阅读2分钟

问题描述

小F正在使用一个骑士跳跃方式的拨号器。这个拨号器是一个类似电话键盘的 3x4 矩阵,每个数字对应一个单元格,骑士只能站在蓝色数字单元格上进行跳跃(数字 1 到 9 和 0)。骑士的移动方式和国际象棋中的马相同:它可以垂直移动两个单元格并水平移动一个单元格,或水平移动两个单元格并垂直移动一个单元格,形成 "L" 形。## 拨号器

问题理解

我们需要计算骑士在 n 次跳跃后可以形成的不同电话号码的数量。骑士的跳跃方式类似于国际象棋中的马,即它可以垂直移动两个单元格并水平移动一个单元格,或水平移动两个单元格并垂直移动一个单元格,形成 "L" 形。

数据结构的选择逻辑

  1. 跳跃规则

    • 我们使用一个字典 jumps 来存储每个数字可以跳到的下一个数字。例如,数字 1 可以跳到数字 6 和 8
  2. 动态规划数组

    • 我们使用一个二维数组 dp,其中 dp[i][j] 表示在 i 次跳跃后,骑士在数字 j 上可以形成的不同电话号码的数量。

算法步骤

  1. 初始化

    • 当 i = 0 时,dp[0][j] = 1,因为骑士可以从任何一个数字开始,且不需要跳跃。
  2. 状态转移

    • 对于每个数字 j,我们可以根据骑士的跳跃规则,计算出它可以跳到的下一个数字。
    • 例如,如果骑士当前在数字 1,它可以跳到数字 6 和 8
    • 因此,dp[i+1][next_number] += dp[i][j],其中 next_number 是骑士从 j 可以跳到的数字。
  3. 最终结果

    • 最终的结果是 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)