|
| 1 | +/* |
| 2 | +⭐️ 문제 정보 ⭐️ |
| 3 | +문제 : 159993 - 미로 탈출 |
| 4 | +레벨 : Level 2 |
| 5 | +링크 : https://school.programmers.co.kr/learn/courses/30/lessons/159993 |
| 6 | +*/ |
| 7 | + |
| 8 | +/** NOTE |
| 9 | + * - BFS 2번이 관건 |
| 10 | + * - 굳이 시작 지점부터의 거리를 계속 갖고 다닐 필요가 없다 => 이러면 BFS 2번 사이에 거리를 저장하고 있어야 해서 구조가 복잡해진다. |
| 11 | + * - 첫번째 BFS : 시작 지점에서 레버까지의 최단 거리 계산 |
| 12 | + * - 두번째 BFS : 레버에서 출구까지의 최단 거리 계산 |
| 13 | + * - 두 거리의 합이 답이 된다. |
| 14 | + * - 각 BFS 결과 도달할 수 없는 경우가 있다면 -1 반환 |
| 15 | + * - 큐 구현을 Map으로 해봤다. |
| 16 | + */ |
| 17 | + |
| 18 | +class Queue { |
| 19 | + queue = new Map(); |
| 20 | + head = 0; |
| 21 | + tail = 0; |
| 22 | + |
| 23 | + constructor() {} |
| 24 | + |
| 25 | + get size() { |
| 26 | + return this.tail - this.head; |
| 27 | + } |
| 28 | + |
| 29 | + enqueue(element) { |
| 30 | + this.queue.set(this.tail++, element); |
| 31 | + } |
| 32 | + |
| 33 | + dequeue() { |
| 34 | + const ret = this.queue.get(this.head); |
| 35 | + if (!ret) { |
| 36 | + return undefined; |
| 37 | + } |
| 38 | + this.queue.delete(this.head++); |
| 39 | + return ret; |
| 40 | + } |
| 41 | + |
| 42 | + isEmpty() { |
| 43 | + return this.head === this.tail; |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +function BFS(maps, start, goal) { |
| 48 | + const R = maps.length; |
| 49 | + const C = maps[0].length; |
| 50 | + const visited = Array.from({ length: R }, () => |
| 51 | + Array.from({ length: C }, () => false) |
| 52 | + ); // 숫자 값을 저장해서 거리 저장에 활용할수도 있음 |
| 53 | + const dir = [ |
| 54 | + [0, 1], |
| 55 | + [0, -1], |
| 56 | + [1, 0], |
| 57 | + [-1, 0], |
| 58 | + ]; |
| 59 | + const queue = new Queue(); |
| 60 | + |
| 61 | + queue.enqueue([start, 0]); |
| 62 | + visited[start.r][start.c] = true; |
| 63 | + |
| 64 | + while (!queue.isEmpty()) { |
| 65 | + const [pos, dist] = queue.dequeue(); |
| 66 | + |
| 67 | + if (pos.r === goal.r && pos.c === goal.c) { |
| 68 | + return dist; |
| 69 | + } |
| 70 | + |
| 71 | + // 상하좌우 이동, 이동 가능한 경우에만 큐에 넣는다. |
| 72 | + for (const [dirR, dirC] of dir) { |
| 73 | + const newR = pos.r + dirR; |
| 74 | + const newC = pos.c + dirC; |
| 75 | + |
| 76 | + if (newR < 0 || newR >= R || newC < 0 || newC >= C) continue; |
| 77 | + if (maps[newR][newC] === "X") continue; |
| 78 | + if (visited[newR][newC]) continue; |
| 79 | + |
| 80 | + visited[newR][newC] = true; |
| 81 | + queue.enqueue([{ r: newR, c: newC }, dist + 1]); |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + // goal에 도달할 수 없는 경우 |
| 86 | + return -1; |
| 87 | +} |
| 88 | + |
| 89 | +function solution(maps) { |
| 90 | + const R = maps.length; |
| 91 | + const C = maps[0].length; |
| 92 | + |
| 93 | + // 지도 탐색 |
| 94 | + let S, E, L; |
| 95 | + for (let r = 0; r < R; r++) { |
| 96 | + for (let c = 0; c < C; c++) { |
| 97 | + if (maps[r][c] === "S") S = { r, c }; |
| 98 | + else if (maps[r][c] === "E") E = { r, c }; |
| 99 | + else if (maps[r][c] === "L") L = { r, c }; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + // S-L 최단 거리 구하기 |
| 104 | + const distToLever = BFS(maps, S, L); |
| 105 | + if (distToLever === -1) return -1; |
| 106 | + |
| 107 | + // L-E 최단 거리 구하기 |
| 108 | + const distToExit = BFS(maps, L, E); |
| 109 | + if (distToExit === -1) return -1; |
| 110 | + |
| 111 | + return distToLever + distToExit; |
| 112 | +} |
0 commit comments