LeetCode 286中等图
墙与门 图解题解
这道题到底在问什么
房间里有门、墙和空房间,给每个空房间填最近门的距离。
- 示例
- INF/门/墙矩阵 → 每格最近门距离
最优解:一步一步想明白
- 3从每个空房间找最近门,会重复搜索。
- 4把所有门同时入队,多源 BFS 一层层扩散,第一次到达就是最短距离。
- 5多源 BFS:把所有门(0)同时入队,距离 0。墙(-1,灰)不可走,空房间(∞)待填。本例有左上、右下两个门。
- 6两个门同时向四周扩一圈:相邻空房间填 1(距最近门 1 步)。
- 7再外扩一圈:(0,2)、(2,0) 填 2。墙 -1 自动绕过、已填的格不再重复。
- 8关键帧:所有门同时向外扩散,每个房间第一次被触到时的层数 = 到最近门的距离。这就是多源 BFS 比「逐房间各自找门」快的原因。
- 11一句话记住:把所有门同时入队,多源 BFS 一层层扩散,第一次到达就是最短距离。
- 20这题学完不要乱跳,下一步去对应专题 /leetcode-animation/ds?k=graph 连刷同类题;卡住时用 AI 答疑问“我的状态定义哪里不稳”。
⚠️ 容易写错的地方
✗ 错:从每个空房间各自 BFS 找最近门
✓ 对:反过来:所有门一起多源 BFS 向外扩
逐房间 BFS 是 O((mn)²);多源 BFS 一遍只 O(mn)。
✗ 错:BFS 时还要比较取最小值
✓ 对:第一次到达就是最近(BFS 按层扩)
多源 BFS 谁先碰到就是最近门,无需再比较。
✗ 错:穿过墙或重复访问
✓ 对:墙(-1)跳过、只填 ∞(未访问)格
墙不可走;已填的格不再入队,防重复。
完整代码(Python / C++ / Java)
Python
class Solution:
def wallsAndGates(self, rooms):
from collections import deque
rows, cols = len(rooms), len(rooms[0])
q = deque((r, c) for r in range(rows) for c in range(cols) if rooms[r][c] == 0)
while q:
r, c = q.popleft()
for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and rooms[nr][nc] == 2147483647:
rooms[nr][nc] = rooms[r][c] + 1
q.append((nr, nc))C++
class Solution {
public:
void wallsAndGates(vector<vector<int>>& rooms) {
int m = rooms.size(), n = rooms[0].size();
queue<pair<int,int>> q;
for (int r=0;r<m;r++) for (int c=0;c<n;c++) if (rooms[r][c] == 0) q.push({r,c});
int d[5] = {1,0,-1,0,1};
while (!q.empty()) {
auto [r,c] = q.front(); q.pop();
for (int k=0;k<4;k++) {
int nr=r+d[k], nc=c+d[k+1];
if (nr>=0&&nr<m&&nc>=0&&nc<n&&rooms[nr][nc]==INT_MAX) {
rooms[nr][nc] = rooms[r][c] + 1;
q.push({nr,nc});
}
}
}
}
};Java
class Solution {
public void wallsAndGates(int[][] rooms) {
int m=rooms.length,n=rooms[0].length;
Queue<int[]> q = new ArrayDeque<>();
for(int r=0;r<m;r++) for(int c=0;c<n;c++) if(rooms[r][c]==0) q.offer(new int[]{r,c});
int[] d={1,0,-1,0,1};
while(!q.isEmpty()){
int[] cur=q.poll();
for(int k=0;k<4;k++){
int nr=cur[0]+d[k], nc=cur[1]+d[k+1];
if(nr>=0&&nr<m&&nc>=0&&nc<n&&rooms[nr][nc]==Integer.MAX_VALUE){
rooms[nr][nc]=rooms[cur[0]][cur[1]]+1;
q.offer(new int[]{nr,nc});
}
}
}
}
}套路模板 · 多源 BFS
# 多源 BFS 骨架
q = deque(所有门的坐标) # 所有源同时入队,距离 0
while q:
r, c = q.popleft()
for 四个方向 nr, nc:
if 在界内 and rooms[nr][nc]==∞: # 只填未访问的空房间
rooms[nr][nc] = rooms[r][c] + 1
q.append((nr, nc))复杂度
时间复杂度
O(m·n)
每个格子最多进出队一次
空间复杂度
O(m·n)
队列最多装一层格子
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 墙与门 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
核心思路是什么?+
把所有门同时入队做多源 BFS,一层层向外扩;每个空房间第一次被触到时的层数就是到最近门的距离。墙跳过、已填不重复。
这道题为什么用「图」,换最直接的暴力解会差在哪?+
图抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。