本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、题目描述:
935. 骑士拨号器 - 力扣(LeetCode) (leetcode-cn.com)
象棋骑士有一个独特的移动方式,它可以垂直移动两个方格,水平移动一个方格,或者水平移动两个方格,垂直移动一个方格(两者都形成一个 L 的形状)。
象棋骑士可能的移动方式如下图所示:
我们有一个象棋骑士和一个电话垫,如下所示,骑士只能站在一个数字单元格上(即蓝色单元格)。
给定一个整数 n,返回我们可以拨多少个长度为 n 的不同电话号码。
你可以将骑士放置在任何数字单元格上,然后你应该执行 n - 1 次移动来获得长度为 n 的号码。所有的跳跃应该是有效的骑士跳跃。
因为答案可能很大,所以输出答案模 10^9 + 7.
示例 1:
输入:n = 1
输出:10
解释:我们需要拨一个长度为1的数字,所以把骑士放在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
解释:注意取模
提示:
- 1 <= n <= 5000
二、思路分析:
dp更新的逻辑在于第k步dp(i,j)的值,等于k-1步再运动一次能够到达(i,j)的所有dp(i+row,j+col)位置的求和。
三、AC 代码:
from copy import deepcopy
class Solution:
def knightDialer(self, N: int) -> int:
dp1 = [[1 for _ in range(3)] for _ in range(4)]
dp1[3][0],dp1[3][2] = 0,0
dlist = [(1,2),(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),(-2,1),(-1,2)]
for k in range(1,N):
dp0 = deepcopy(dp1)
dp1 = [[0 for _ in range(3)] for _ in range(4)]
for row in range(4):
for col in range(3):
#角落里两个点始终不更新
if (row,col)==(3,0) or (row,col)==(3,2):continue
for i,j in dlist:
if row+i<=3 and row+i>=0 and col+j<=2 and col+j>=0:
dp1[row][col] = dp1[row][col]+dp0[row+i][col+j]
res = sum(map(sum,dp1))%(10**9+7)
return(res)
四、总结:
这是一套很典型的动态规划题了。