携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情 >>
骑士拨号器
象棋骑士有一个独特的移动方式,它可以垂直移动两个方格,水平移动一个方格,或者水平移动两个方格,垂直移动一个方格(两者都形成一个 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
解释: 注意取模
示例4:
输入: s = "abc3[cd]xyz"
输出: "abccdcdcdxyz"
提示:
1 <= n <= 5000
解题思路:
1. 只有1位数的号码,可以使用5作为起点,因此n = 1时返回10;
2. 当n > 1时,我们不能选择5作为起点,其他数字均可以。此时记录以每个数字为结尾的号码数,然后根据跳转关系,计算下一长度的各位号码数即可;
3. 最终返回全部位置上,号码数的加和。
我的答案:
/**
* @param {number} n
* @return {number}
*/
var knightDialer = function(n) {
if (n === 1) return 10;
let mod = 1e9 + 7;
let arr = [2,2,2,2,3,0,3,2,2,2];
let c = 2;
while (c < n) {
let nArr = arr.slice();
nArr[0] = (arr[4] + arr[6]) % mod;
nArr[1] = (arr[8] + arr[6]) % mod;
nArr[2] = (arr[9] + arr[7]) % mod;
nArr[3] = (arr[4] + arr[8]) % mod;
nArr[4] = (arr[0] + arr[3] + arr[9]) % mod;
nArr[6] = (arr[0] + arr[1] + arr[7]) % mod;
nArr[7] = (arr[2] + arr[6]) % mod;
nArr[8] = (arr[1] + arr[3]) % mod;
nArr[9] = (arr[4] + arr[2]) % mod;
c += 1;
arr = nArr;
}
return arr.reduce((a,i) => (a+i)%mod);
};
最后
如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )