542.01矩阵
给定一个由0
和1
组成的矩阵mat
,请输出一个大小相同的矩阵,其中每一个格子是mat
中对应位置元素到最近的0
的距离。两个相邻元素间的距离为1
。
示例1
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
示例2
输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]
提示
m == mat.length
n == mat[i].length
1 <= m, n <= 10^4
1 <= m * n <= 10^4
mat[i][j]
is either 0 or 1mat
中至少有一个0
代码
\\ 方法1 两次遍历
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int m = mat[0].size(), n = mat.size();
vector<vector<int>> res(n,vector<int>(m,INT_MAX - 1));
// 第一次从左上向右下遍历
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
// 如果当前mat元素为0,则其到0的最短距离为0
if (mat[i][j] == 0) res[i][j] = 0;
else
{
// 如果当前mat元素为1,则取其及其上方单元格值加1的最小值
if (j > 0)
res[i][j] = min(res[i][j],res[i][j - 1] + 1);
// 如果当前mat元素为1,则取其及其左方单元格值加1的最小值
if (i > 0)
res[i][j] = min(res[i][j],res[i - 1][j] + 1);
}
}
// 第二次从右下向左上遍历
for (int i = n - 1; i >= 0; i--)
{
for (int j = m - 1; j >= 0; j--)
if (mat[i][j] == 0) res[i][j] = 0;
else
{
// 如果当前mat元素为1,则取其及其下方单元格值加1的最小值
if (j < m - 1)
res[i][j] = min(res[i][j],res[i][j + 1] + 1);
// 如果当前mat元素为1,则取其及其右方单元格值加1的最小值
if (i < n - 1)
res[i][j] = min(res[i][j],res[i + 1][j] + 1);
}
}
return res;
// 方法2 广度优先搜索
private:
static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
vector<vector<int>> dist(m, vector<int>(n));
vector<vector<int>> seen(m, vector<int>(n));
queue<pair<int, int>> q;
// 将所有的 0 添加进初始队列中
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == 0) {
q.emplace(i, j);
seen[i][j] = 1;
}
}
}
// 广度优先搜索
while (!q.empty()) {
auto [i, j] = q.front();
q.pop();
for (int d = 0; d < 4; ++d) {
int ni = i + dirs[d][0];
int nj = j + dirs[d][1];
if (ni >= 0 && ni < m && nj >= 0 && nj < n && !seen[ni][nj]) {
dist[ni][nj] = dist[i][j] + 1;
q.emplace(ni, nj);
seen[ni][nj] = 1;
}
}
}
return dist;
}
}
994.腐烂的橘子
在给定的m x n
网格grid
中,每个单元格可以有以下三个值之一:
- 值
0
代表空单元格; - 值
1
代表新鲜橘子; - 值
2
代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。
示例1
输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例2
输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例3
输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。
提示
m == grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j]
仅为0
、1
或2
思路
- 创建一个队列,找到所有的腐烂橘子(数字2),将他们入队;
- 向每一个腐烂橘子的四周遍历,将新鲜橘子(数字1)传染(改为2),同时时间+1;
- 删除队列中的已经传染过别的橘子的腐烂橘子,将新被传染的橘子入队
几种情况
- 网格中没有新鲜橘子,直接返回0;
- 网格中有新鲜橘子,但没有腐烂橘子,直接返回-1;
- 类似示例2,有新鲜橘子不会被传染。这时要统计网格中的新鲜橘子个数,如果被传染的个数和新鲜的个数不同,说明有新鲜橘子没有被传染,要返回-1。
代码
const int dx[4] = {1,0,0,-1};
const int dy[4] = {0,1,-1,0};
int time[10][10]; // 传染到每个新鲜橘子的时间
int res; // 结果
int cnt = 0; // 当前新鲜橘子的个数
int orangesRotting(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
queue<pair<int,int>> record;
// 统计腐烂橘子的位置和新鲜橘子的个数
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (grid[i][j] == 2)
record.push(make_pair(i,j));
if (grid[i][j] == 1)
cnt++;
}
}
// 如果没有新鲜橘子,直接返回0
if (!cnt)
return 0;
// 如果有新鲜橘子但没有腐烂橘子,直接返回-1
if (record.empty())
return -1;
// 广度优先遍历
while (!record.empty())
{
// 取出队头的腐烂橘子
pair<int,int> point = record.front();
record.pop();
// 腐烂橘子向四周传染
for (int i = 0; i < 4; i++)
{
int x = point.first + dx[i];
int y = point.second + dy[i];
// 如果超出了网格范围,就直接向下个方向传染
if (x < 0 || x >= m || y < 0 || y >= n)
{continue;}
// 如果腐烂橘子的周围有新鲜橘子
if (grid[x][y] == 1)
{
// 将新鲜橘子传染
grid[x][y] = 2;
// 传染时间是上个腐烂橘子传染时间+1
time[x][y] = time[point.first][point.second] + 1;
// 记录当前的总时间
res = time[x][y];
// 把新被传染的橘子入队
record.push(make_pair(x,y));
// 新鲜橘子的个数-1
cnt--;
}
}
}
// 如果最后没有新鲜橘子了,就输出总时间,如果有新鲜橘子剩下,就返回-1
return cnt?-1:res;
}
本文题目及部分解答来自力扣:
https://leetcode-cn.com/problems/rotting-oranges/