[Java] 1844 게임 맵 최단거리
1. 문제
게임 맵 최단거리
- https://school.programmers.co.kr/learn/courses/30/lessons/1844
- 검은색 : 벽
- 흰색 : 길
- 최단거리 리턴
- 단, 맨 마지막 그림처럼 목적지 주변이 벽으로 막혀 있으면 -1 리턴
2. 접근 방법
- 시작점 (0, 0)에서 BFS를 시작한다.
- 갈 수 있는 길(maps[r][c] == 1) 이동
- 방문할 때마다 현재까지의 칸수 기록
- 도착점 (n - 1, m - 1)에 도달하면 해당 칸에 기록된 값이 최단거리
- BFS 탐색이 끝났는데 도착점에 도달하지 못했다면 -1 반환
3. 정답 코드
BFS
import java.util.*;
class Solution {
static class Point {
int x,y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public int solution(int[][] maps) {
int n = maps.length;
int m = maps[0].length;
// 방향 배열 (상, 하, 좌, 우)
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
Queue<Point> queue = new LinkedList<>();
queue.add(new Point(0, 0));
// BFS로 거리 누적하기 (여기서 시작점 1로 잡음)
// maps 배열에 거리 값 직접 지정
while (!queue.isEmpty()) {
Point p = queue.poll();
for (int i = 0; i < 4; i++) {
int nx = p.x + dx[i];
int ny = p.y + dy[i];
// 맵 범위 확인
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
// 길이고 아직 방문하지 않은 경우
if (maps[nx][ny] == 1) {
maps[nx][ny] = maps[p.x][p.y] + 1; // 거리 누적
queue.add(new Point(nx, ny));
}
}
}
return maps[n-1][m-1] == 1 ? -1 : maps[n-1][m-1];
}
}
4방향 탐색
dx = {-1, 1, 0, 0}
dy = {0, 0, -1, 1}
- x좌표 (행 번호) 기준 -1는 한칸 위, +1은 한 칸 아래
- 위쪽으로 한 칸 (x - 1)
- 아래쪽으로 한 칸 (x + 1)
- y좌표 (열 번호) 기준 -1는 좌로 한 칸 이동, +1은 우로 한 칸 이동
- 왼쪽으로 한 칸 (y - 1)
- 오른쪽으로 한 칸 (y + 1)
- for (int i = 0; i < 4; i++) 루프 돌면서 (x + dx[i], y + dy[i]) 계산하면 상하좌우 네 방향 전부 확인 가능
방문한 칸을 따로 배열에 저장 안 하고 maps 에 거리값 덮어쓴 이유
2가지 방법이 있다.
- 방문 여부 + 거리 저장을 maps에 덮어 쓰기 (이게 내가 한 방법)
- maps[x][y] == 1 아직 방문하지 않은 길
- maps[x][y] == maps[이전칸] + 1
- 이렇게 해서 몇 번째 칸에 도달했는지 거리 기록
- 이렇게 하면 visited[][] 안만들어도 됨
- maps는 그대로 두고 visited, dist배열 따로쓰기
- boolean[][] visited → 방문여부 체크
- int[][] dist → 해당 칸까지의 최단 거리 저장
- 이렇게 하면 원본 맵 보존 가능
maps[nx][ny] = maps[x][y] + 1;
단순히 방문 체크 하는게 아니라 여기까지 오는데 몇 칸 걸렸는지 바로 저장 가능
맵 범위 확인
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
- BFS에서 상하좌우로 이동할 때 새로운 좌표 (nx, ny)를 만든다
- 근데 만약에 (nx, ny)가 맵 밖으로 나가면 ArrayIndexOutOfBoundsException 에러가 나기 때문에 좌표가 맵 안에 있는지 확인하는 로직이다
- nx < 0 → 위로 나가서 맵 밖 (행 음수)
- ny < 0 → 왼쪽으로 나가서 맵 밖 (열 음수)
- nx >= n → 아래로 나가서 맵 밖 (행이 전체 크기 n 이상)
- ny >= m → 오른쪽으로 나가서 맵 밖 (열이 전체 크기 m이상)