935. 骑士拨号器

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

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

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

给定一个整数 n,返回我们可以拨多少个长度为 n 的不同电话号码。

你可以将骑士放置在任何数字单元格上,然后你应该执行 n - 1 次移动来获得长度为 n 的号码。所有的跳跃应该是有效的骑士跳跃。

因为答案可能很大,所以输出答案模 109 + 7.

思路

这个问题可以使用动态规划来解决。我们可以使用一个二维数组 dp[i][j] 来表示在第 j 步时,骑士位于数字键 i 的不同拨号方式数量。然后,我们根据骑士在数字键盘上的移动规则,递推地计算出 dp 数组的值。

解题方法

动态规划数组初始化: 我们初始化一个大小为 10xN 的二维数组 dp,其中 N 是给定的步数。初始化时,每个位置的值都为 1,表示在任意一步骑士都可以到达该数字键。

动态规划递推: 我们按照骑士在数字键盘上的移动规则,逐步更新 dp 数组的值。具体来说,对于每个数字键 i 和每一步 j,我们根据骑士的移动规则计算出从键 i 到达其他键的可能路径数量,并将结果保存在 dp[i][j] 中。

计算总的拨号方式数量: 最后,我们计算 dp 数组中最后一列的所有值的总和,即为所求的结果。

复杂度

时间复杂度:O(N),其中 N 是给定的步数。我们需要填充一个大小为 10xN 的二维数组,每个位置的填充都是常数时间的操作。
空间复杂度:O(N),我们需要使用一个大小为 10xN 的二维数组来存储动态规划的结果。

class Solution {
public:
    int knightDialer(int n) {
        const int MOD = 1e9 + 7;
        vector<vector<long long>> dp(10,vector<long long>(n,1)); 
        for(int j=1;j<n;j++)
        {
            dp[0][j] = (dp[6][j-1]+dp[4][j-1]) % MOD;
            dp[1][j] = (dp[6][j-1]+dp[8][j-1]) % MOD;
            dp[2][j] = (dp[7][j-1]+dp[9][j-1]) % MOD;
            dp[3][j] = (dp[4][j-1]+dp[8][j-1]) % MOD;
            dp[4][j] = (dp[9][j-1]+dp[3][j-1]+dp[0][j-1]) % MOD;
            dp[5][j] = 0;
            dp[6][j] = (dp[7][j-1]+dp[1][j-1]+dp[0][j-1]) % MOD;
            dp[7][j] = (dp[2][j-1]+dp[6][j-1]) % MOD;
            dp[8][j] = (dp[3][j-1]+dp[1][j-1]) % MOD;
            dp[9][j] = (dp[4][j-1]+dp[2][j-1]) % MOD; 
        }

        long long ret = 0;
        for(int i=0;i<10;i++)
            ret = (ret + dp[i][n-1]) % MOD;

        return ret;
    }
};



//dp[0][j] = dp[6][j-1]+dp[4][j-1];
//dp[1][j] = dp[6][j-1]+dp[8][j-1];
//dp[2][j] = dp[7][j-1]+dp[9][j-1];
//dp[3][j] = dp[4][j-1]+dp[8][j-1];
//dp[4][j] = dp[9][j-1]+dp[3][j-1]+dp[0][j-1];
//dp[5][j] = 0;
//dp[6][j] = dp[7][j-1]+dp[1][j-1]+dp[0][j-1];
//dp[7][j] = dp[2][j-1]+dp[6][j-1];
//dp[8][j] = dp[3][j-1]+dp[1][j-1];
//dp[9][j] = dp[4][j-1]+dp[2][j-1];

//dp[j] = 

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值