【刷题打卡】935. 骑士拨号器

64 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、题目描述:

935. 骑士拨号器 - 力扣(LeetCode) (leetcode-cn.com)

象棋骑士有一个独特的移动方式,它可以垂直移动两个方格,水平移动一个方格,或者水平移动两个方格,垂直移动一个方格(两者都形成一个 L 的形状)。

象棋骑士可能的移动方式如下图所示:

image.png

我们有一个象棋骑士和一个电话垫,如下所示,骑士只能站在一个数字单元格上(即蓝色单元格)。

image.png

给定一个整数 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)

四、总结:

这是一套很典型的动态规划题了。