代码思路分析
该题目旨在解决一个骑士拨号器问题,其中骑士在3x4矩阵上按照国际象棋中马的移动方式进行跳跃。目标是计算长度为n的所有不同电话号码的数量。
-
初始化:
- 定义了一个
MOD变量,用于存储取模的值(10^9 + 7),以避免整数溢出。 - 定义了一个
dialer矩阵,虽然这个矩阵在后续代码中并未使用,但它表示了拨号器的布局。 - 定义了一个
moves字典,用于存储每个数字可以跳跃到的其他数字。
- 定义了一个
-
动态规划数组初始化:
- 使用一个二维数组
dp来存储中间结果,其中dp[step][num]表示在第step步时,以数字num结尾的电话号码的数量。 - 初始化
dp数组的第一行,表示在第0步时,每个数字都可以作为起点,因此它们的数量都是1。
- 使用一个二维数组
-
动态规划状态转移:
- 遍历每一步(从1到
n-1)和每个数字(从0到9)。 - 对于每个数字
num,遍历它可以跳跃到的所有数字next_num。 - 更新
dp[step][num]的值,将其增加dp[step-1][next_num]的值,表示在第step-1步以next_num结尾的电话号码数量可以跳跃到第step步以num结尾的电话号码。 - 对
dp[step][num]取模,以避免整数溢出。
- 遍历每一步(从1到
-
计算最终结果:
- 遍历
dp[n-1]数组,计算所有以任意数字结尾的电话号码的总数,并对结果取模。
- 遍历
改进方向
-
去除未使用的变量:
dialer矩阵在代码中并未使用,可以将其删除。
-
优化空间复杂度:
- 由于只需要知道前一步和后一步的状态,可以使用一维数组代替二维数组来存储动态规划的结果,从而节省空间。
-
预处理输入:
moves字典是固定的,可以将其定义为常量或在函数外部初始化,以避免在每次函数调用时都重新创建它。
-
代码简洁性:
- 可以进一步简化代码,例如通过合并循环和条件语句,以及使用更清晰的变量名。
代码如下
def solution(n: int) -> int:
MOD = 10**9 + 7
moves = {
1: [6, 8],
2: [7, 9],
3: [4, 8],
4: [3, 9, 0],
5: [],
6: [1, 7, 0],
7: [2, 6],
8: [1, 3],
9: [2, 4],
0: [4, 6]
}
# 初始化动态规划数组
dp = [[0] * 10 for _ in range(n)]
# 初始状态:第0步时,每个数字都可以作为起点
for num in range(10):
dp[0][num] = 1
# 动态规划状态转移
for step in range(1, n):
for num in range(10):
for next_num in moves[num]:
dp[step][num] += dp[step-1][next_num]
dp[step][num] %= MOD
# 计算最终结果
result = sum(dp[n-1]) % MOD
return result