
0번부터 n - 1번까지 n개의 방이 있고, 0번 방을 뺀 나머지는 모두 잠겨 있다.
각 방에는 다른 방을 여는 열쇠가 들어 있으며, rooms[i]는 i번 방에 있는 열쇠 목록이다.
0번 방에서 출발해 모든 방에 들어갈 수 있으면 true, 아니면 false를 반환한다.
입력: rooms = [[1],[2],[3],[]]
출력: true
// 0 → 1 → 2 → 3 순서로 모든 방에 들어갈 수 있다
입력: rooms = [[1,3],[3,0,1],[2],[0]]
출력: false
// 2번 방 열쇠는 2번 방 안에만 있다
방을 노드, 열쇠를 간선으로 보면 그래프 문제가 된다.
0번 노드에서 출발해 모든 노드에 도달할 수 있는가?
결국 0번에서 시작하는 그래프 탐색(BFS/DFS)을 한 번 돌리고, 방문한 방의 수가 전체 방의 수와 같은지 비교하면 된다.
Set에 기록한다.0번 방을 넣고 시작한다.방문한 방 수 === 전체 방 수를 반환한다.function canVisitAllRooms(rooms: number[][]): boolean {
const visited = new Set<number>();
let keys = [0];
while (keys.length) {
const room = keys.shift();
visited.add(room);
for (const key of rooms[room]) {
if (!visited.has(key)) keys.push(key);
}
}
return rooms.length === visited.size;
};
제출은 통과하지만 다듬을 곳이 두 군데 있다.
지금 코드는 방을 꺼낼 때 방문 처리를 한다. 그래서 아직 꺼내지 않은 방이 큐에 여러 번 들어갈 수 있고, 그 방의 열쇠 목록도 여러 번 다시 훑게 된다.
넣을 때 방문 처리를 하면 각 방은 큐에 정확히 한 번만 들어간다.
shift() 대신 스택(pop())을 쓴다Array.prototype.shift()는 뒤의 요소를 한 칸씩 당기므로 O(n)이다.
이 문제는 방문 순서는 상관없고 도달 가능 여부만 묻기 때문에, pop()(O(1))을 쓰는 DFS로 바꿔도 답은 같다.
덤으로 strict 모드에서는 shift()의 반환 타입이 number | undefined라 rooms[room]에서 타입 에러가 난다. while문 안에서 꺼낸 값을 !로 단언하면 해결된다.
function canVisitAllRooms(rooms: number[][]): boolean {
const visited = new Set<number>([0]);
const stack = [0];
while (stack.length) {
const room = stack.pop()!;
for (const key of rooms[room]) {
if (visited.has(key)) continue;
visited.add(key);
stack.push(key);
}
}
return visited.size === rooms.length;
}
N, 전체 열쇠 수를 K라고 하면visited와 스택에 방 번호가 최대 N개 들어간다.shift()보다 pop()이 싸다.