Leetcode 每日一题和每日一题的下一题刷题笔记 27/30
写在前面
这是我参与更文挑战的第27天,活动详情查看:更文挑战
快要毕业了,才发现自己被面试里的算法题吊起来锤。没办法只能以零基础的身份和同窗们共同加入了力扣刷题大军。我的同学们都非常厉害,他们平时只是谦虚,口头上说着自己不会,而我是真的不会。。。乘掘金鼓励新人每天写博客,我也凑个热闹,记录一下每天刷的前两道题,这两道题我精做。我打算每天刷五道题,其他的题目嘛,也只能强行背套路了,就不发在博客里了。
本人真的只是一个菜鸡,解题思路什么的就不要从我这里参考了,编码习惯也需要改进,各位如果想找刷题高手请教问题我觉得去找 宫水三叶的刷题日记 这位大佬比较好。我在把题目做出来之前尽量不去看题解,以免和大佬的内容撞车。
另外我也希望有得闲的大佬提供一些更高明的解题思路给我,欢迎讨论哈!
好了废话不多说开始第二十七天的前两道题吧!
2021.6.27 每日一题
简单来说就是棋盘上有传送门,当走到传送门起点的时候可以传送过去,但只能传一次。这种题还是可以 A*,但是昨天的经历告诉我这里面水太深我把握不住,我还是老老实实 BFS 好一点。。。
去年崩坏三夏活好像就是一个类似这种题的大富翁扔色子棋,屁股后头还有个怪在追自己,还不能让它追上,自己还得把前面的怪排掉,自己还能扔炸弹,那个比这个的变数要多好多,当然和童年桌游比起来还是小巫见大巫。
BFS 的话将节点编号和到达该节点的最少次数作为状态,然后用现在的这个节点之后可能的 6 个步数(也就是下一次)更新后面六个节点的最小次数。因为棋盘是二维的,但是扔色子往前走只能是一维的增加,所以其实暗藏一步把棋盘的编号拉成一维的操作。假设原来的编号是 pxy,现在新的编号是 qx,这两者的关系是
有人会疑惑为什么还要两种编号的转化,反正就是顺着下来走完就完事了。主要是输入里面那些传送门是二维坐标,我这里只能保留这么一步,因为我也不知道棋盘上是传送门格子多还是普通格子多,全转化了一了百了。
写代码,代码里在表示队列的时候会用掉 p 和 q,所以点的坐标不用这两个字母,用 rol 和 col 的 r 和 c 表示,一维编号就是 id。
class Solution {
pair<int, int> id2rc(int id, int n) {
int r = (id - 1) / n, c = (id - 1) % n;
if (r % 2 == 1) {
c = n - 1 - c;
}
return {n - 1 - r, c};
}
public:
int snakesAndLadders(vector<vector<int>> &board) {
int n = board.size();
vector<int> vis(n * n + 1);
queue<pair<int, int>> q;
q.emplace(1, 0);
while (!q.empty()) {
auto p = q.front();
q.pop();
for (int i = 1; i <= 6; i++) {
int nxt = p.first + i;
if (nxt > n * n) {
break;
}
auto rc = id2rc(nxt, n);
if (board[rc.first][rc.second] > 0) {
nxt = board[rc.first][rc.second];
}
if (nxt == n * n) {
return p.second + 1;
}
if (!vis[nxt]) {
vis[nxt] = true;
q.emplace(nxt, p.second + 1);
}
}
}
return -1;
}
};
2021.6.27 每日一题下面的题
简单题不说了。
class Solution {
public:
vector<string> fizzBuzz(int n) {
vector<string> result;
for (int i = 1; i <= n; ++i) result.push_back(to_string(i));
for (int i = 2; i < n; i += 3) result[i] = "Fizz";
for (int i = 4; i < n; i += 5) result[i] = "Buzz";
for (int i = 14; i < n; i += 15) result[i] = "FizzBuzz";
return result;
}
};
小结
BFS 更新最小次数,注意一维编号到二维编号的改变。附带简单题,少用取余数和除法也许能提高效率。
参考链接
无