문제 설명
ROR 게임은 두 팀으로 나누어서 진행하며, 상대 팀 진영을 먼저 파괴하면 이기는 게임입니다. 따라서, 각 팀은 상대 팀 진영에 최대한 빨리 도착하는 것이 유리합니다.
지금부터 당신은 한 팀의 팀원이 되어 게임을 진행하려고 합니다. 다음은 5 x 5 크기의 맵에, 당신의 캐릭터가 (행: 1, 열: 1) 위치에 있고, 상대 팀 진영은 (행: 5, 열: 5) 위치에 있는 경우의 예시입니다.

위 그림에서 검은색 부분은 벽으로 막혀있어 갈 수 없는 길이며, 흰색 부분은 갈 수 있는 길입니다. 캐릭터가 움직일 때는 동, 서, 남, 북 방향으로 한 칸씩 이동하며, 게임 맵을 벗어난 길은 갈 수 없습니다.
아래 예시는 캐릭터가 상대 팀 진영으로 가는 두 가지 방법을 나타내고 있습니다.


위 예시에서는 첫 번째 방법보다 더 빠르게 상대팀 진영에 도착하는 방법은 없으므로, 이 방법이 상대 팀 진영으로 가는 가장 빠른 방법입니다.
만약, 상대 팀이 자신의 팀 진영 주위에 벽을 세워두었다면 상대 팀 진영에 도착하지 못할 수도 있습니다. 예를 들어, 다음과 같은 경우에 당신의 캐릭터는 상대 팀 진영에 도착할 수 없습니다.

게임 맵의 상태 maps가 매개변수로 주어질 때, 캐릭터가 상대 팀 진영에 도착하기 위해서 지나가야 하는 칸의 개수의 최솟값을 return 하도록 solution 함수를 완성해주세요. 단, 상대 팀 진영에 도착할 수 없을 때는 -1을 return 해주세요.
제한 사항
입출력 예
| maps | answer |
|---|---|
| [[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,1],[0,0,0,0,1]] | 11 |
| [[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,0],[0,0,0,0,1]] | -1 |
[출처] 프로그래머스(https://programmers.co.kr/learn/courses/30/lessons/1844)
function solution(maps) { maps[0][0] = 0 const queue = [[0,0]]; let step = 1; const M = maps.length const N = maps[0].length while(queue.length>0) { const size = queue.length; for(let i = 0; i < size; i++) { const [row, col] = queue.shift() if(row===M-1 && col ===N-1) return step if(row+1 < M && maps[row+1][col]===1) { queue.push([row+1, col]) maps[row+1][col] = 0 } if(row-1 >= 0 && maps[row-1][col]===1) { queue.push([row-1, col]) maps[row-1][col] = 0 } if(col+1 < N && maps[row][col+1]===1) { queue.push([row, col+1]) maps[row][col+1] = 0 } if(col-1 >= 0 && maps[row][col-1]===1) { queue.push([row, col-1]) maps[row][col-1] = 0 } } step++ } return -1 }
function solution(maps) { maps[0][0] = 0 const queue = [[0,0]]; let step = 1; const next = [[1,0,-1,0],[0,1,0,-1]] const M = maps.length const N = maps[0].length while(queue.length>0) { const size = queue.length; for(let i = 0; i < size; i++) { const [row, col] = queue.shift() for(let j = 0; j < 4; j++) { let nextRow = row + next[0][j]; let nextCol = col + next[1][j]; if(nextRow >= 0 && nextRow < M && nextCol >= 0 && nextCol < N && maps[nextRow][nextCol] === 1) { if(nextRow == M - 1 && nextCol == N - 1) { return ++step; } queue.push([nextRow, nextCol]); maps[nextRow][nextCol] = 0; } } } step++ } return -1 }
첫 번째 답과 두 번째 답의 로직은 동일하고 탐색할 위치를 구하기 위한 배열을 생성하여 간결하게 코드를 작성하였다.
최단 거리를 구하는 문제이기 때문에 BFS(너비 우선 탐색)을 사용하여 문제를 해결하였다. DFS(깊이 우선 탐색)로도 코드를 작성해보았지만 효율성 테스트에서 통과하지 않았다. BFS는 탐색하는 칸에서 발견한 위치들을 queue에 push하고 해당 칸의 탐색이 끝나면 shift하여 탐색하는 FIFO(선입선출) 방식을 사용하기 때문에 도착 점에 도달한 순간에 탐색을 종료하면 최단 거리를 찾을 수 있다. 반면 DFS는 최단거리를 구하기 위해서는 모든 경로의 탐색을 마쳐야 하기 때문에 DFS보다 불리하다.
이 문제는 상대 팀 진영에 도착하는데 몇 칸을 이동해야 하는 지를 구하는 문제이기 때문에 같은 거리의 탐색이 끝나면 step++를 하면서 값을 도출하였다. DFS는 재귀함수를 사용하여 step+1을 인자로 전달해주면 되지만, BFS는 queue에 계속 탐색해야 할 위치가 push되기 때문에 const size = queue.length;로 같은 거리의 위치들과 새롭게 추가되는 위치를 구분해주었다.
프로젝트 때문에 한동안 코딩 테스트에는 소홀했었는데, 오랜만에 자료구조 관련 문제를 풀면서 예전에 이해했던 내용을 상기할 수 있었다. 다른 자료구조나 알고리즘 관련 문제들을 복습하면서 코딩 테스트 문제들을 꾸준하게 풀어야겠다고 느꼈다.