[LeetCode] 935. Knight Dialer 骑士拨号器
A chess knight can move as indicated in the chess diagram below:
. 
This time, we place our chess knight on any numbered key of a phone pad (indicated above), and the knight makes N-1 hops. Each hop must be from one key to another numbered key.
Each time it lands on a key (including the initial placement of the knight), it presses the number of that key, pressing N digits total.
How many distinct numbers can you dial in this manner?
Since the answer may be large, output the answer modulo 10^9 + 7.
Example 1:
Input: 1
Output: 10
Example 2:
Input: 2
Output: 20
Example 3:
Input: 3
Output: 46
Note:
1 <= N <= 5000
这道题说是有一种骑士拨号器,在一个电话拨号盘上跳跃,其跳跃方式是跟国际象棋中的一样,不会国际象棋的童鞋可以将其当作中国象棋中的马,马走日象飞田。这个骑士可以放在 10 个数字键上的任意一个,但其跳到的下一个位置却要符合其在国际象棋中的规则,也就是走日。现在给了一个整数N,说是该骑士可以跳N次,问能拨出多个不同的号码,并且提示了结果要对一个超大数字取余。看到这里,对于各位刷题老司机来说,肯定能反应过来要用动态规划 Dynamic Programming 了吧,因为数字可能巨大无比,强行暴力递归破解可能会爆栈。这里使用一个二维数组 dp,其中 dp[i][j] 表示骑士第i次跳到数字j时组成的不同号码的个数,那么最终所求的就是将 dp[N-1][j] 累加起来,j的范围是0到9。接下来看状态转移方程怎么写,当骑士在第i次跳到数字j时,考虑其第 i-1 次是在哪个位置,可能有多种情况,先来分析拨号键盘的结构,找出从每个数字能到达的下一个位置,可得如下关系:
0 -> 4, 6
1 -> 6, 8
2 -> 7, 9
3 -> 4, 8
4 -> 3, 9, 0
5 ->
6 -> 1, 7, 0
7 -> 2, 6
8 -> 1, 9
9 -> 4, 2
可以发现,除了数字5之外,每个数字都可以跳到其他位置,其中4和6可以跳到三个不同位置,其他都只能取两个位置。反过来想,可以去的位置,就表示也可能从该位置回来,所以根据当前的位置j,就可以在数组中找到上一次骑士所在的位置,并将其的 dp 值累加上即可,这就是状态转移的方法,由于第一步是把骑士放到任意一个数字上,就要初始化 dp[0][j] 为1,然后进行状态转移就行了,记得每次累加之后要对超大数取余,最后将 dp[N-1][j] 累加起来的时候,也要对超大数取余,参见代码如下:
解法一:
class Solution {
public:
int knightDialer(int N) {
int res = 0, M = 1e9 + 7;
vector<vector<int>> dp(N, vector<int>(10));
vector<vector<int>> path{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 9}, {4, 2}};
for (int i = 0; i < 10; ++i) dp[0][i] = 1;
for (int i = 1; i < N; ++i) {
for (int j = 0; j <= 9; ++j) {
for (int idx : path[j]) {
dp[i][j] = (dp[i][j] + dp[i - 1][idx]) % M;
}
}
}
for (int i = 0; i < 10; ++i) res = (res + dp.back()[i]) % M;
return res;
}
};
我们也可以用递归+记忆数组的方式来写,整体思路和迭代的方法并没有什么区别,之前类似的题目也不少,就不多解释了,可以对照上面的讲解和代码来理解,参见代码如下:
解法二:
class Solution {
public:
int knightDialer(int N) {
int res = 0, M = 1e9 + 7;
vector<vector<int>> memo(N + 1, vector<int>(10));
vector<vector<int>> path{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 9}, {4, 2}};
for (int i = 0; i < 10; ++i) {
res = (res + helper(N - 1, i, path, memo)) % M;
}
return res;
}
int helper(int n, int cur, vector<vector<int>>& path, vector<vector<int>>& memo) {
if (n == 0) return 1;
if (memo[n][cur] != 0) return memo[n][cur];
int res = 0, M = 1e9 + 7;
for (int idx : path[cur]) {
res = (res + helper(n - 1, idx, path, memo)) % M;
}
return memo[n][cur] = res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/935
类似题目:
Letter Combinations of a Phone Number
参考资料:
https://leetcode.com/problems/knight-dialer/
https://leetcode.com/problems/knight-dialer/discuss/189265/Concise-Java-DP-Solution
https://leetcode.com/problems/knight-dialer/discuss/189271/Java-Top-Down-Memo-DP-O(N)
[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)
[LeetCode] 935. Knight Dialer 骑士拨号器的更多相关文章
- LeetCode 935. Knight Dialer
原题链接在这里:https://leetcode.com/problems/knight-dialer/ 题目: A chess knight can move as indicated in the ...
- [Swift]LeetCode935. 骑士拨号器 | Knight Dialer
A chess knight can move as indicated in the chess diagram below: . This time, we place o ...
- [Leetcode][动态规划] 第935题 骑士拨号器
一.题目描述 国际象棋中的骑士可以按下图所示进行移动: 我们将 “骑士” 放在电话拨号盘的任意数字键(如上图所示)上,接下来,骑士将会跳 N-1 步 ...
- 【LeetCode】935. Knight Dialer 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划TLE 空间换时间,利用对称性 优化空间复杂 ...
- 【leetcode】935. Knight Dialer
题目如下: A chess knight can move as indicated in the chess diagram below: . This time, we p ...
- 935. Knight Dialer
A chess knight can move as indicated in the chess diagram below: . This time, we place o ...
- 02_电话拨号器intent说明
怎么在第一个Activity打开第二个Activity?在一个Activity中打开另外一个Activity,实际上之前已经做过,就是电话拨号器. package com.itheima.callne ...
- Mono for Android—初体验之“电话拨号器”
1.Main.axml文件: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmln ...
- Android 笔记 day2 拨号器
随机推荐
- objectarx 得到有宽度的多段的轮廓
使用到的命令是:_.wmfout和_.import以及PEdit步骤:1.先通过_.wmfout和_.import得到轮廓线,得到的轮廓线是一个块.方法如下: //ssname:选择的有宽度的多段线 ...
- 201771010105—达拉草 实验一 软件工程准备—<软件工程构建之法—初步了解和认识>
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 想要成为一名优秀的Java程序员,你需要这8个锦囊
私底下,隔三差五就有读者问我:"二哥,怎么样才能像你一样,成为一名优秀的 Java 开发者呢?"假如把"怎么才能像你一样"去掉的话,这个问题就是一个好问题,否则 ...
- git工作中常用操作总结
这篇文章主要记录下工作中常用的git操作.主要是对之前文章记录的问题做个总结,这个其实在idea中操作更加简单 别名配置 在敲git 命令时,其实可以使用别名,比如 commit可以配置为ci 下面是 ...
- http协议概览
这里我只是对一些知识进行简单的整理,方便自己理解记忆,还有很多不完善的地方,更多细节,需要查看书籍或者其他文章 http协议的发展过程 HTTP 是基于 TCP/IP 协议的应用层协议.它不涉及数据包 ...
- SpringBoot整合Mybatis对单表的增、删、改、查操作
一.目标 SpringBoot整合Mybatis对单表的增.删.改.查操作 二.开发工具及项目环境 IDE: IntelliJ IDEA 2019.3 SQL:Navicat for MySQL 三. ...
- 从0开始搭建kafka客户端
上一节,我们实现了搭建kafka集群.本节我们将从0开始,使用Java,搭建kafka客户端生产消费模型. 1.创建maven项目2.kafka producer3.kafka consumer4.结 ...
- 「从零单排HBase 04」HBase高性能查询揭秘
先给结论吧:HBase利用compaction机制,通过大量的读延迟毛刺和一定的写阻塞,来换取整体上的读取延迟的平稳. 1.为什么要compaction 在上一篇 HBase读写 中我们提到了,HBa ...
- Hyperledger Fabric1.4环境搭建
参考文档:https://www.cnblogs.com/cbkj-xd/p/11067790.html 1. 设置下载源为阿里源 sudo vim /etc/apt/sources.list 在配置 ...
- Excel之在单元格中生成随机密码
公式 =CHAR(INT(RAND()*26+97))&INT(RAND()*10)&CHAR(INT(RAND()*26+97))&INT(RAND()*10) 分析 CHA ...