题目描述
给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
样例
输入:
0 0 0
0 1 0
0 0 0
输出:
0 0 0
0 1 0
0 0 0
输入:
0 0 0
0 1 0
1 1 1
输出:
0 0 0
0 1 0
1 2 1
提示
- 给定矩阵的元素个数不超过 10000。
- 给定矩阵中至少有一个元素是 0。
- 矩阵中的元素只在四个方向上相邻: 上、下、左、右。
算法
(宽度优先搜索) $O(nm)$
- 定义一个队列,初始时将所有 0 元素的坐标进队;定义答案数组 dis,0 元素位置的值为 0,其余为 -1。
- 对这个队列开始进行宽度优先搜索,每次扩展上下左右四个方向,若发现新的位置在 dis 中值为 -1,则更新新位置的答案为当前位置答案加 1。
时间复杂度
- 宽度优先搜索每个位置仅被遍历一次,故时间复杂度为 $O(nm)$。
空间复杂度
- 需要额外的空间存放队列和每个点的距离,故空间复杂度为 $O(nm)$。
C++ 代码
class Solution {
public:
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int n = matrix.size(), m = matrix[0].size();
queue<pair<int, int>> q;
vector<vector<int>> dis(n, vector<int>(m, -1));
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (matrix[i][j] == 0) {
dis[i][j] = 0;
q.push(make_pair(i, j));
}
while (!q.empty()) {
pair<int, int> sta = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int x = sta.first + dx[i], y = sta.second + dy[i];
if (x < 0 || x >= n || y < 0 || y >= m || dis[x][y] != -1)
continue;
dis[x][y] = dis[sta.first][sta.second] + 1;
q.push(make_pair(x, y));
}
}
return dis;
}
};
老哥,为啥这里判断语句改为&&会超时?
你是指 bfs 中的判断语句?这个是排除非法情况的,如果其中任何一个条件满足,则不应该扩展
嗯,我 的意思是bfs里面的if改为x>=0&&x<n…满足的话再延伸,但我这样处理就超时了
哦?你可以私信我代码给你看看
python 这个题目lc上7k ms。。。一直以为tle是2s呢。。看起来是10s?
python 高密度访问数组会比 C++ 慢不少的
写了个DFS 成功TLE了 T_T
请问一下 dfs 时间复杂度是多少呀 不太会算时间复杂度
我一开始把这个题想得跟329 比较像。 后来发现如果用329的方法, 是不是会有loop
对的,用dp的话状态之间会存在循环依赖,会导致状态无法被计算出来。
y总 为啥用dp的话状态之间会存在循环依赖呀
我有一个疑问就是,这里的dis[x][y] = dis[sta.first][sta.second] + 1; 只会算到一次,而且第一次算的时候一定就是求的最小的值,也就是离0最近的距离。是怎么确保做到这样的呢?因为queue 里面存的pair, 在同一层里存进去的值是相等的,而且越是后面存进来的pair, 距离0的距离越远。 所以要是前面有被计算过, 那么前面计算的值一定是最小的。
BFS相比于DFS,其中一个特性就是BFS可以求出“最小值”,比如最短距离,最小步数等等。
BFS的队列可以分段来看,层层扩展:第一次先把所有距离是0的点都加进队列,第二步把所有距离是1的点加入队列,依次类推,所以可以保证求出的距离就是最小值。
感觉写bfs是很久很久以前的事了,写得最多的就是dfs了。所以这道题很习惯性的也想用dfs,其实还是没有对这类题型理解透彻,看到解答的时候就想说,嗯,对, 是应该用宽度优先搜索。 dfs会慢很多很多。 尤其是如果走到一条错误的路上去了的话,要一直绕下去, 而且感觉dfs会有很多重复计算, 不懂,也许我的写法里面dfs有很多重复计算。