Problem Overview
LeetCode 841 — Keys and Rooms — gives you n rooms labeled 0 through n-1. Room 0 starts unlocked. Every other room is locked, but each room contains a list of keys to other rooms. Starting from room 0, you can collect keys and use them to enter locked rooms. The question: can you visit every room?
The problem is a single yes/no reachability question. You need to determine whether all n rooms are reachable from room 0 given the directed key relationships. The rooms field is a list of lists: rooms[i] contains the keys found inside room i. Keys can repeat, and you may have keys to rooms you have already visited.
The constraints keep the problem manageable and make brute-force unnecessary. A systematic graph traversal is sufficient to visit all reachable rooms in one pass.
- n rooms labeled 0 to n-1; room 0 is always unlocked at the start
- rooms[i] is a list of keys found inside room i — each key opens one room
- You can only enter a room if you hold its key (except room 0)
- Keys may repeat; you may already hold a key to a room you re-encounter
- Constraints: 2 <= n <= 1000; 0 <= rooms[i].length <= 1000; total keys <= 3000
- Return true if all rooms can be visited, false otherwise
This Is a Graph Reachability Problem
Rooms are nodes in a directed graph. Keys are directed edges: a key k found in room i means there is a directed edge from node i to node k. Room 0 is the source node. The question becomes: starting at node 0, can you reach every other node by following directed edges?
This is exactly the definition of graph reachability from a single source. The visited set tracks which rooms have been entered. When the traversal ends, if visited.size equals n, all rooms were reachable. If visited.size is less than n, at least one room had no path of keys leading to it from room 0.
Once you see the graph framing, the algorithm writes itself. Reach for your standard DFS or BFS template, substitute rooms for nodes and keys for neighbors, and check the visited count at the end. No specialized data structure or clever trick is needed — this is pure traversal.
Reframe as "Can You Reach All Nodes from Node 0?"
This problem is literally "can you reach all nodes from node 0 in a directed graph?" — once you see that framing, it is a textbook DFS/BFS. The rooms are nodes, the keys are directed edges, and the visited set is your standard traversal bookkeeping. Recognizing this mapping immediately in an interview eliminates the need to invent a new approach.
DFS Approach
The DFS solution starts by adding room 0 to the visited set, then recursively visits every room reachable via keys. For each room visited, iterate its key list; for each key that points to an unvisited room, mark it visited and recurse into it. After DFS completes, compare the size of the visited set to n.
The visited set serves two roles: it prevents revisiting rooms already entered (avoiding infinite cycles if keys loop back) and it provides the final count for the reachability check. Every room added to visited is a room that was successfully entered. A final count of n means every room was entered.
DFS is naturally recursive in Python and most interview languages. The call stack depth is at most n, which is safe given the constraint n <= 1000. An iterative DFS with an explicit stack is also straightforward and avoids any recursion limit concerns in Python for larger inputs.
- 1Initialize visited = {0} (room 0 is unlocked from the start)
- 2Define dfs(room): for each key in rooms[room]: if key not in visited: add key to visited; call dfs(key)
- 3Call dfs(0) to start the traversal from room 0
- 4After DFS completes, check: return len(visited) == n
- 5If all rooms reachable, visited size equals n → return True; otherwise False
BFS Alternative
The BFS solution uses a queue instead of recursion. Initialize the queue with room 0 and mark it visited. While the queue is non-empty, dequeue a room, iterate its keys, and enqueue any unvisited rooms while marking them visited. After the queue empties, check if visited.size equals n.
BFS processes rooms level by level — first room 0, then all rooms reachable directly from room 0, then rooms reachable in two hops, and so on. The order of discovery differs from DFS, but the final visited set is identical for any given input. BFS is often preferred in interviews by candidates who find iterative code easier to write without bugs under pressure.
Both approaches have O(V + E) time complexity where V is the number of rooms and E is the total number of keys across all rooms. Space complexity is O(V) for the visited set plus the stack or queue. For this problem, V <= 1000 and total keys <= 3000, so both are very fast in practice.
BFS and DFS Give Identical Results for Reachability
BFS and DFS give identical results for reachability — both explore all nodes reachable from the source and no others. Choose whichever you are more comfortable coding quickly in an interview. DFS recursive is the shortest code; BFS iterative with a deque is the most explicit. Neither has a performance advantage on this problem.
Walk-Through Examples
Example 1: rooms = [[1],[2],[3],[]]. Room 0 contains key 1. Room 1 contains key 2. Room 2 contains key 3. Room 3 contains no keys. DFS from 0: visit 0 → find key 1 → visit 1 → find key 2 → visit 2 → find key 3 → visit 3 → no keys. visited = {0,1,2,3}. Size 4 == n 4 → return true.
Example 2: rooms = [[1,3],[3,0,1],[2],[0]]. Start at room 0 → keys 1 and 3. Visit 1 → keys 3, 0, 1 (all visited or about to be). Visit 3 → key 0 (already visited). From the initial traversal, room 2 is never reached because no room reachable from 0 holds key 2 (room 2 only holds key 2, and you need to enter room 2 to get it — a catch-22). visited = {0,1,3}. Size 3 != n 4 → return false.
The second example illustrates why the problem is non-trivial: a room can be permanently inaccessible if its key is only found inside itself or inside other inaccessible rooms. The visited set naturally captures this — any room not added during traversal was never reachable.
- 1Example 1 — rooms=[[1],[2],[3],[]]: start room 0 → key 1 → key 2 → key 3 → no keys; visited={0,1,2,3}; size 4==4 → true
- 2Example 2 — rooms=[[1,3],[3,0,1],[2],[0]]: start room 0 → keys 1 and 3
- 3Visit room 1 → keys 3, 0, 1 (all already visited or queued)
- 4Visit room 3 → key 0 (already visited)
- 5Room 2 is never reached — no reachable room holds key 2
- 6visited={0,1,3}; size 3 != 4 → false
Code Walkthrough — Python and Java
Python DFS with a set: def canVisitAllRooms(rooms): visited = {0}; def dfs(room): [dfs(key) for key in rooms[room] if key not in visited and not visited.add(key)]; dfs(0); return len(visited) == len(rooms). Cleaner iterative DFS: visited = {0}; stack = [0]; while stack: room = stack.pop(); for key in rooms[room]: if key not in visited: visited.add(key); stack.append(key); return len(visited) == len(rooms). Time: O(V+E). Space: O(V).
Java DFS with a Set: public boolean canVisitAllRooms(List<List<Integer>> rooms) { Set<Integer> visited = new HashSet<>(); visited.add(0); Deque<Integer> stack = new ArrayDeque<>(); stack.push(0); while (!stack.isEmpty()) { int room = stack.pop(); for (int key : rooms.get(room)) { if (visited.add(key)) { stack.push(key); } } } return visited.size() == rooms.size(); }. HashSet.add returns false if the element was already present, so the visited.add(key) check doubles as the "not yet visited" guard.
Both implementations follow the same structure: initialize visited and a frontier (stack or queue) with room 0, expand until the frontier is empty, then compare visited size to total rooms. The Python iterative and Java versions are nearly identical in structure and are the safest to write from memory under interview pressure.
Check Visited Count AFTER Traversal Completes — Not During
Don't check 'all rooms have been entered' during DFS or BFS — check AFTER the traversal completes by comparing visited set size with total rooms. Checking during traversal leads to premature returns. The traversal must fully exhaust the frontier before you can know whether all rooms are reachable. The single comparison len(visited) == n at the end is all you need.