饭不食,水不饮,题必须刷
C语言免费动漫教程,和我一起打卡! 《光天化日学C语言》
LeetCode 太难?先看简单题! 《C语言入门100例》
数据结构难?不存在的! 《数据结构入门》
LeetCode 太简单?算法学起来! 《夜深人静写算法》
在给定的网格中,每个单元格可以有以下三个值之一:
1)值 0 代表空单元格;
2)值 1 代表新鲜橘子;
3)值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。
样例输入: [ 2 1 1 1 1 0 0 1 1 ] \left[ \begin{matrix} 2 & 1 & 1 \\ 1 & 1 & 0 \\ 0 & 1 & 1\end{matrix} \right] ⎣⎡210111101⎦⎤
样例输出: 4
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
}
};
vector>& grid
代表的是一个二维数组,用来代表二维矩阵的橘子位置,&
作为引用,用来加速参数传递。int
,代表哪个时刻下所有橘子都腐烂了。LeetCode 994. 腐烂的橘子
首先,将所有腐烂的橘子(值为 2 的格子)的位置进行哈希(标记访问时间为 0),然后压入队列。利用广搜,扩散范围。对于相邻的格子,如下几种情况分别处理:
1)格子没有被访问过,且遇到一个新鲜橘子(值为 1 的格子),哈希后压入队列,并且标记格子的访问时间为相邻那个扩散到它的格子的访问时间 + 1。
2)格子没有被访问过,且遇到空位置,不做任何处理;
3)格子被访问过,不做任何处理;
搜索完毕,遍历所有格子,如果存在新鲜橘子,返回 -1;否则,取最访问时间最大的进行返回。
int dir[4][2] = {
{0, 1}, // right
{1, 0}, // down
{0, -1}, // left
{-1, 0}, // up
};
const int maxn = 120;
class Solution {
int n, m;
int visited[maxn];
queue <int> que;
int getVisitedId(int x, int y) { // (1)
return x * m + y;
}
void getPosByVisitedId(int visitedId, int &x, int &y) { // (2)
x = visitedId / m;
y = visitedId % m;
}
void init(vector<vector<int>>& mat) {
while(!que.empty()) { // (3)
que.pop();
}
memset(visited, -1, sizeof(visited)); // (4)
n = mat.size(); // (5)
m = mat[0].size(); // (6)
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(2 == mat[i][j]) { // (7)
visited[ getVisitedId(i, j) ] = 0;
que.push( getVisitedId(i, j) );
}
}
}
}
bool outOfBound(int x, int y) {
return x < 0 || x >= n || y < 0 || y >= m;
}
void bfs(vector<vector<int>>& mat) {
while(!que.empty()) {
int vid = que.front(); // (8)
int x, y;
getPosByVisitedId(vid, x, y); // (9)
que.pop();
for(int i = 0; i < 4; ++i) { // (10)
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(outOfBound(tx, ty)) {
continue;
}
int nextvid = getVisitedId(tx, ty); // (11)
if(mat[tx][ty] == 1 && visited[nextvid] == -1) {
visited[nextvid] = visited[vid] + 1;
que.push(nextvid);
}
}
}
}
int output(int *visited, vector<vector<int>>& mat) {
int maxv = 0;
for(int i = 0; i < n; ++i) {
vector <int> ans;
for(int j = 0; j < m; ++j) {
int vid = getVisitedId(i, j);
if(mat[i][j] == 1 && visited[ vid ] == -1) {
return -1; // (12)
}
if( visited[ vid ] > maxv ) {
maxv = visited[ vid ]; // (13)
}
}
}
return maxv;
}
public:
int orangesRotting(vector<vector<int>>& grid) {
init(grid);
bfs(grid);
return output(visited, grid);
}
};
memset
初始化将所有矩阵元素的标记位全部置为-1
,关于memset
更多用法,可以参考:《C/C++ 面试 100 例》(六)memset 全网最全总结;1)一维的
vector
可以当数组用,二维的vector
可以当矩阵用。
2)利用memset
可以将标记置为-1
代表尚未访问。
3)广搜的过程,就是不断把状态压入队列尾,不断取出队列头部状态的过程,由于状态可能是多维的,所以我们一般考虑将多维状态变成一维,这个称为序列化;再在弹出队列的时候,将一维状态还原成多维,这个称为反序列化。一般就是通过进制转换来完成。
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
大致题集一览:
为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」。
联系作者,或者扫作者主页二维码加群,加入刷题行列吧
让天下没有难学的算法
C语言免费动漫教程,和我一起打卡! 《光天化日学C语言》
入门级C语言真题汇总 《C语言入门100例》
几张动图学会一种数据结构 《画解数据结构》
组团学习,抱团生长 《算法入门指引》
竞赛选手金典图文教程 《夜深人静写算法》