There are n
rooms labeled from 0
to n - 1
and all the rooms are locked except for room 0
. Your goal is to visit all the rooms. However, you cannot enter a locked room without having its key.
When you visit a room, you may find a set of distinct keys in it. Each key has a number on it, denoting which room it unlocks, and you can take all of them with you to unlock the other rooms.
Given an array rooms
where rooms[i]
is the set of keys that you can obtain if you visited room i
, return true
if you can visit all the rooms, or false
otherwise.
Example 1:
Input: rooms = [[1],[2],[3],[]] Output: true Explanation: We visit room 0 and pick up key 1. We then visit room 1 and pick up key 2. We then visit room 2 and pick up key 3. We then visit room 3. Since we were able to visit every room, we return true.
Example 2:
Input: rooms = [[1,3],[3,0,1],[2],[0]] Output: false Explanation: We can not enter room number 2 since the only key that unlocks it is in that room.
Constraints:
n == rooms.length
2 <= n <= 1000
0 <= rooms[i].length <= 1000
1 <= sum(rooms[i].length) <= 3000
0 <= rooms[i][j] < n
rooms[i]
are unique.This problem asks whether it's possible to visit all rooms given a set of keys found in each room. The rooms are represented as a graph where rooms are nodes and keys are edges. We can solve this using either Depth-First Search (DFS) or Breadth-First Search (BFS).
Core Idea: Both DFS and BFS systematically explore the graph, starting from room 0. They mark visited rooms to avoid cycles and ensure all reachable rooms are explored. If the number of visited rooms equals the total number of rooms, all rooms are accessible.
1. Depth-First Search (DFS):
Approach: The DFS algorithm recursively explores the graph. It starts at room 0 and explores as deeply as possible along each branch before backtracking. A visited
set (or array) tracks visited rooms.
Time Complexity: O(V + E), where V is the number of vertices (rooms) and E is the number of edges (keys). We visit each room and each key at most once.
Space Complexity: O(V) in the worst case, due to the recursive call stack (depth of recursion could be V in a worst-case scenario – a very deep, linked graph). The visited
set also contributes to the space complexity.
2. Breadth-First Search (BFS):
Approach: BFS explores the graph level by level. It uses a queue to store rooms to be visited. It starts by adding room 0 to the queue. It then repeatedly dequeues a room, marks it as visited, and adds its adjacent (reachable) rooms to the queue.
Time Complexity: O(V + E). Similar to DFS, we visit each room and each key at most once.
Space Complexity: O(V) in the worst case. The queue can hold all the rooms in the worst-case scenario (a completely connected graph).
Code Examples (Python):
DFS:
class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
n = len(rooms)
visited = [False] * n
visited[0] = True # Mark room 0 as visited initially
count = 1 # Initialize count of visited rooms to 1 (for room 0)
def dfs(room):
nonlocal count # Access the outer count variable
for key in rooms[room]:
if not visited[key]:
visited[key] = True
count += 1
dfs(key)
dfs(0)
return count == n
BFS:
from collections import deque
class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
n = len(rooms)
visited = [False] * n
visited[0] = True
queue = deque([0])
count = 1
while queue:
room = queue.popleft()
for key in rooms[room]:
if not visited[key]:
visited[key] = True
count += 1
queue.append(key)
return count == n
Both solutions achieve the same result. The choice between DFS and BFS often depends on specific problem characteristics; in this case, both are equally efficient. The BFS implementation might be slightly preferable in some cases because it uses iterative approach, avoiding potential stack overflow issues that could arise with very deep recursive calls in DFS (though unlikely with the problem constraints). However, for this particular problem, the difference is minimal.