题目描述
思路解析动画文字版
最朴素的想法:维护一堆已拿到的钥匙,每轮扫一遍看能开哪些还没开的门。可你会一次次重新检查那些早就开过的房间,钥匙一多就大量重复。
转折:把它看成图——房间是节点,钥匙是有向边。从 0 开始 BFS/DFS,每进一个房就立刻标记 visited,只对没访问过的房入队。这样每个房只处理一次,不再回头重扫。最后数 visited 等于房间总数就是 true。
建图 · 0 入队:画成图:rooms[0]=[1]、rooms[1]=[2]、rooms[2]=[3]、rooms[3]=[],即三条有向边 0→1→2→3。起点 0 标记 visited 并入队,作为遍历的源头。
出队 0 · 看它的钥匙:取出 0(标橙=正在处理),它已访问。看它手上的钥匙 rooms[0]=[1],准备去开 1 号房。
0→1 · 1 没访问过 → 入队:沿边 0→1:房 1 还没访问,所以拿钥匙开门、标记 visited、入队。0 处理完变绿(done)。
出队 1 · 看它的钥匙:取出 1 处理。它的钥匙 rooms[1]=[2],指向房 2。
1→2 · 2 没访问过 → 入队:沿边 1→2:房 2 没访问过,开门、标记、入队。注意每次进房第一件事就是标 visited——这是防止绕回来死循环的关键。
出队 2 · 1→2 已访问(负例:跳过):取出 2 处理,它的钥匙 rooms[2]=[3]。设想此刻又冒出一把指回 1 的钥匙:房 1 已经在 visited 里——直接跳过、不再入队。这就是负例:已访问的房一律不重复处理。
2→3 · 3 没访问过 → 入队:沿边 2→3:房 3 没访问,开门、标记、入队。
出队 3 · 没钥匙了 · 队列空:取出 3 处理,rooms[3]=[] 没钥匙了。没有新房可入队,队列空,遍历结束。
判断 · 数 visited:数一下 visited:4 个,正好等于房间总数 4 → 全部可达,返回 true。若某房没人给钥匙、永远进不了 visited,最终 len(visited) 小于 N,就返回 false。
凡是「从一个点出发能不能走到所有点」「有几个连通块」,都用 BFS/DFS 数可达节点。钥匙房间、被围绕的区域、省份数量,全是这一类。
参考代码
class Solution: def canVisitAllRooms(self, rooms): seen = {0} stack = [0] while stack: room = stack.pop() for key in rooms[room]: if key not in seen: seen.add(key) stack.append(key) return len(seen) == len(rooms)复杂度
- 时间复杂度:O(N+E),N 个房各出队一次,E 把钥匙各检查一次
- 空间复杂度:O(N),visited 集合 + 队列最多装 N 个房
可套用的代码模板
记住骨架:起点先标记、邻居只处理没访问的、入队前立刻加 visited、最后数 visited。把队列换成递归就是 DFS,效果一样。
Python
# 「从起点能到达哪些点」都套visited = {start}; q = deque([start])while q: u = q.popleft() for v in graph[u]: if v not in visited: # 只走没访问的 visited.add(v); q.append(v)# len(visited) == N ? 全连通易错点
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
二进制矩阵中的最短路径
LeetCode 1091 · 中等 · 沿着 图论套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题