LeetCode Everyday - 骑士拨号器

91 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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时返回102. 当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);
};

最后

如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )