반응형
문제 이해하기
주어진 문제는 다음과 같습니다:
- 미로는 O(빈칸), X(벽), S(시작점), L(레버), E(출구)로 구성됩니다.
- S에서 L로, L에서 E로 이동해야 합니다.
- O만 지나갈 수 있으며, X는 벽이라 지나갈 수 없습니다.
- 최단 거리로 이동하는 방법을 찾는 게 목표입니다.
예제 입력
["SOOOL", "XXXXO", "OOOOO", "OXXXX", "OOOOE"]
위 미로에서 우리는 S(0, 0) → L(0, 4) → E(4, 4)로 이동하는 경로를 찾아야 합니다.
알고리즘을 어떻게 접근할까?
이 문제를 해결하기 위해 두 가지 개념을 사용합니다:
1. 미로 탐색
2. 최단 거리 찾기
최단 거리 탐색에 적합한 BFS
최단 거리를 찾기 위해 BFS (Breadth-First Search), 즉 너비 우선 탐색을 사용합니다. BFS는 가까운 곳부터 차례로 탐색하며 최단 경로를 보장하는 장점이 있습니다.
코드 작성하기
1. 미로에서 주요 위치 찾기
미로에서 S, L, E의 좌표를 찾습니다.
let start, lever, end;
// S, L, E의 위치를 찾기
maps.forEach((row, rowIndex) => {
if (row.includes('S')) start = [rowIndex, row.indexOf('S')];
if (row.includes('L')) lever = [rowIndex, row.indexOf('L')];
if (row.includes('E')) end = [rowIndex, row.indexOf('E')];
});
2. BFS 함수 작성하기
BFS는 큐(queue)를 이용해 진행합니다.
다음 코드를 통해 start에서 destination까지 최단 거리를 계산합니다.
function bfs(start, destination) {
const queue = [[...start, 0]]; // [x, y, 거리]
const visited = Array.from({ length: maps.length }, () =>
Array(maps[0].length).fill(false)
);
visited[start[0]][start[1]] = true;
while (queue.length) {
const [x, y, dist] = queue.shift();
// 목적지 도착 시 거리 반환
if (x === destination[0] && y === destination[1]) return dist;
// 상하좌우 탐색
for (const [dx, dy] of [[0, 1], [1, 0], [0, -1], [-1, 0]]) {
const nx = x + dx;
const ny = y + dy;
// 이동 가능 조건 확인
if (
nx >= 0 && nx < maps.length &&
ny >= 0 && ny < maps[0].length &&
maps[nx][ny] !== 'X' &&
!visited[nx][ny]
) {
visited[nx][ny] = true;
queue.push([nx, ny, dist + 1]);
}
}
}
return -1; // 목적지에 도달 불가
}
3. 경로 계산하기
이제 S → L과 L → E로 나눠 계산합니다.
const toLever = bfs(start, lever); // S에서 L까지
const toExit = bfs(lever, end); // L에서 E까지
if (toLever === -1 || toExit === -1) {
return -1; // 도달 불가능
}
return toLever + toExit;
코드 전체
최종 코드는 다음과 같습니다:
function solution(maps) {
let start, lever, end;
maps.forEach((row, rowIndex) => {
if (row.includes('S')) start = [rowIndex, row.indexOf('S')];
if (row.includes('L')) lever = [rowIndex, row.indexOf('L')];
if (row.includes('E')) end = [rowIndex, row.indexOf('E')];
});
function bfs(start, destination) {
const queue = [[...start, 0]];
const visited = Array.from({ length: maps.length }, () =>
Array(maps[0].length).fill(false)
);
visited[start[0]][start[1]] = true;
while (queue.length) {
const [x, y, dist] = queue.shift();
if (x === destination[0] && y === destination[1]) return dist;
for (const [dx, dy] of [[0, 1], [1, 0], [0, -1], [-1, 0]]) {
const nx = x + dx;
const ny = y + dy;
if (
nx >= 0 && nx < maps.length &&
ny >= 0 && ny < maps[0].length &&
maps[nx][ny] !== 'X' &&
!visited[nx][ny]
) {
visited[nx][ny] = true;
queue.push([nx, ny, dist + 1]);
}
}
}
return -1;
}
const toLever = bfs(start, lever);
const toExit = bfs(lever, end);
if (toLever === -1 || toExit === -1) return -1;
return toLever + toExit;
}
알고리즘 TIP 💡
- BFS와 DFS의 차이:
DFS는 끝까지 파고드는 방식으로 탐색합니다. 반면, BFS는 가까운 거리부터 탐색하므로 최단 거리 문제에 적합합니다. - 방문 처리:
이미 방문한 곳을 다시 방문하면 무한 루프에 빠질 수 있습니다. visited 배열로 방문 여부를 기록하세요. - 큐(queue) 사용:
BFS는 큐를 사용해 탐색의 순서를 관리합니다. 배열의 shift와 push로 쉽게 구현할 수 있습니다.
마치며
오늘은 미로에서 최단 거리를 찾는 방법을 알아보았습니다. BFS를 활용하면 미로 같은 문제를 효율적으로 해결할 수 있어요.
반응형
'Algorithm > Programmers' 카테고리의 다른 글
[프로그래머스] PCCP 기출문제 / 1번 동영상 재생기 / Lv1 / JS / 접근법, 코드, 추가테스트케이스 (0) | 2024.11.25 |
---|---|
[프로그래머스] 연습문제 / 마법의 엘리베이터 / Lv2 / JS / 접근법 (0) | 2024.11.24 |
[프로그래머스] 연습문제 / 달리기 경주 / Lv1 / JS / 접근법 (0) | 2024.11.23 |
[프로그래머스] 연습문제 / 콜라 문제 / Lv1 / JS / 탐욕알고리즘 (0) | 2024.11.23 |
[프로그래머스] 연습문제 / 삼총사 / Lv1 / JS (0) | 2024.11.21 |