Graphs - DFS · Medium
LeetCode 841: Keys and Rooms — solution
Solve LeetCode 841 with a graph DFS from room 0 that follows every key found, then checks whether every room was reached — O(n + k) time, O(n) space.
Problem in plain words
There are n rooms numbered 0 to n - 1. Only room 0 is unlocked at the start. Each room contains a list of keys, and key x opens room x. You may enter any room you have a key for, collect its keys, and repeat. Return true if you can eventually enter every room.
Example: rooms = [[2], [], [1]]. Room 0 gives key 2, room 2 gives key 1, and room 1 is then open, so the answer is true. With [[1], [], [0]], nothing ever opens room 2, so the answer is false.
Intuition
Treat each room as a node and each key as a directed edge from the room containing it to the room it opens. The question becomes: are all nodes reachable from node 0? That is a plain reachability search — a depth-first search (or BFS) with a visited array.
Approach
- Create a boolean
visitedarray, mark room0visited and push it on a stack. - Pop a room and look at each key in it.
- If the key's room is not visited yet, mark it and push it.
- When the stack is empty, return
trueonly if every room is marked (or the visited count equalsn).
Dry run
rooms = [[2], [], [1]]
| Pop | Keys found | Newly visited | Stack after |
|---|---|---|---|
| 0 | 2 | 2 | [2] |
| 2 | 1 | 1 | [1] |
| 1 | — | — | [] |
Visited = {0, 1, 2}, all three rooms, so return true.
Java solution
class Solution {
public boolean canVisitAllRooms(List<List<Integer>> rooms) {
int n = rooms.size();
boolean[] visited = new boolean[n];
Deque<Integer> stack = new ArrayDeque<>();
visited[0] = true;
stack.push(0);
int count = 1;
while (!stack.isEmpty()) {
int room = stack.pop();
for (int key : rooms.get(room)) {
if (!visited[key]) {
visited[key] = true;
count++;
stack.push(key);
}
}
}
return count == n;
}
}Python solution
class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
visited = [False] * len(rooms)
visited[0] = True
stack = [0]
while stack:
room = stack.pop()
for key in rooms[room]:
if not visited[key]:
visited[key] = True
stack.append(key)
return all(visited)Complexity
| Measure | Cost | Why |
|---|---|---|
| Time | O(n + k) | Each room is pushed once and each of the k keys is examined once. |
| Space | O(n) | The visited array and the stack hold at most n rooms. |
Edge cases and common mistakes
- Forgetting to mark room 0 — if it is not marked, a key back to room 0 pushes it again (harmless but wasteful) and the final count may be off.
- Marking when popping instead of when pushing — a room can then be pushed many times. Marking on push keeps the work linear.
- Duplicate keys or a key to the current room — the visited check ignores them.
- Single room — with
n = 1, the answer istrueimmediately.
›DFS or BFS?
Either one. We only care about which rooms are reachable, not the order or distance, so any traversal that visits each node once works. BFS with a queue gives the same answer.
