개발자를 희망하는 죠르디가 카카오에 면접을 보러 왔습니다.
코로나 바이러스 감염 예방을 위해 응시자들은 거리를 둬서 대기를 해야하는데 개발 직군 면접인 만큼
아래와 같은 규칙으로 대기실에 거리를 두고 앉도록 안내하고 있습니다.
- 대기실은 5개이며, 각 대기실은 5x5 크기입니다.
- 거리두기를 위하여 응시자들 끼리는 맨해튼 거리1가 2 이하로 앉지 말아 주세요.
- 단 응시자가 앉아있는 자리 사이가 파티션으로 막혀 있을 경우에는 허용합니다.
예를 들어,
위 그림처럼 자리 사이에 파티션이 존재한다면 맨해튼 거리가 2여도 거리두기를 지킨 것입니다. | 위 그림처럼 파티션을 사이에 두고 앉은 경우도 거리두기를 지킨 것입니다. | 위 그림처럼 자리 사이가 맨해튼 거리 2이고 사이에 빈 테이블이 있는 경우는 거리두기를 지키지 않은 것입니다. |
응시자가 앉아있는 자리(P )를 의미합니다. |
빈 테이블(O )을 의미합니다. |
파티션(X )을 의미합니다. |
5개의 대기실을 본 죠르디는 각 대기실에서 응시자들이 거리두기를 잘 기키고 있는지 알고 싶어졌습니다. 자리에 앉아있는 응시자들의 정보와 대기실 구조를 대기실별로 담은 2차원 문자열 배열 places
가 매개변수로 주어집니다. 각 대기실별로 거리두기를 지키고 있으면 1을, 한 명이라도 지키지 않고 있으면 0을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.
places
의 행 길이(대기실 개수) = 5
places
의 각 행은 하나의 대기실 구조를 나타냅니다.places
의 열 길이(대기실 세로 길이) = 5places
의 원소는 P
,O
,X
로 이루어진 문자열입니다.
places
원소의 길이(대기실 가로 길이) = 5P
는 응시자가 앉아있는 자리를 의미합니다.O
는 빈 테이블을 의미합니다.X
는 파티션을 의미합니다.places
에 담겨 있는 5개 대기실의 순서대로, 거리두기 준수 여부를 차례대로 배열에 담습니다.places | result |
---|---|
[["POOOP", "OXXOX", "OPXPX", "OOXOX", "POXXP"], ["POOPX", "OXPXP", "PXXXO", "OXXXO", "OOOPP"], ["PXOPX", "OXOXP", "OXPOX", "OXXOP", "PXPOX"], ["OOOXX", "XOOOX", "OOOXX", "OXOOX", "OOOOO"], ["PXPXP", "XPXPX", "PXPXP", "XPXPX", "PXPXP"]] |
[1, 0, 1, 1, 1] |
입출력 예 #1
첫 번째 대기실
No. | 0 | 1 | 2 | 3 | 4 |
0 | P | O | O | O | P |
1 | O | X | X | O | X |
2 | O | P | X | P | X |
3 | O | O | X | O | X |
4 | P | O | X | X | P |
두 번째 대기실
No. | 0 | 1 | 2 | 3 | 4 |
0 | P | O | O | P | X |
1 | O | X | P | X | P |
2 | P | X | X | X | O |
3 | O | X | X | X | O |
4 | O | O | O | P | P |
세 번째 대기실
No. | 0 | 1 | 2 | 3 | 4 |
0 | P | X | O | P | X |
1 | O | X | O | X | P |
2 | O | X | P | O | X |
3 | O | X | X | O | P |
4 | P | X | P | O | X |
네 번째 대기실
No. | 0 | 1 | 2 | 3 | 4 |
0 | O | O | O | X | X |
1 | X | O | O | O | X |
2 | O | O | O | X | X |
3 | O | X | O | O | X |
4 | O | O | O | O | O |
다섯 번째 대기실
No. | 0 | 1 | 2 | 3 | 4 |
0 | P | X | P | X | P |
1 | X | P | X | P | X |
2 | P | X | P | X | P |
3 | X | P | X | P | X |
4 | P | X | P | X | P |
두 번째 대기실을 제외한 모든 대기실에서 거리두기가 지켜지고 있으므로, 배열 [1, 0, 1, 1, 1]을 return 합니다.
※ 공지 - 2022년 4월 25일 테스트케이스가 추가되었습니다.
두 테이블 T1, T2가 행렬 (r1, c1), (r2, c2)에 각각 위치하고 있다면, T1, T2 사이의 맨해튼 거리는 |r1 - r2| + |c1 - c2| 입니다. ↩
출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
처음 설계를 진행할때는 BFS로 풀려고 했다... 내 실수였다.. 이게 아닌데..
처음에 5*5배열을 받으면 P인 지점을 찾아서 그 x,y,count,findX,findY값으로 넣어준다.
1) x: 현재 돌고 있는 x값
2) y: 현재 돌고 있는 y값
3) count: 체크하고 있는 P의 좌표로 부터 얼마만큼 이동했는지
4) findX, findY : 체크하고 있는 P의 좌표
1. 큐를 하나씩 뽑으면서 아래과정을 체크
박스를 안에 있는지 체크
1) 그 좌표가 P 이면서 거리가 2이하이며 체크하고 있는 좌표가 아니라면 0을 리턴
2) 그 좌표가 O이면서 거리가 1이하이며, 방문하지 않았다면
큐에 그 값을 푸쉬
또한 방문했다는 표시
2, 이를 반복해서 큐가 비어서 while문을 나왔다면 1을 리턴
- solution함수에서는 5*5 배열을 위해 하나씩 넣으면서 리턴된 값을 answer에 추가
function disCheck(arr){
arr = arr.map((element)=>{
return element.split("");
})
var queue = [];
var visitArr = Array.from(Array(5), ()=> new Array(5).fill(false));
for(var dy=0;dy<arr.length;dy++){
for(var dx = 0;dx<arr.length;dx++){
if(arr[dy][dx]==="P"){
queue.push([dx,dy,0,dx,dy]);
visitArr[dy][dx] = true;
}
}
}
var moveX = [1,-1,0,0];
var moveY = [0,0,-1,1];
while(queue.length!==0){
for(var i = 0;i<queue.length;i++){
let[x,y,count,findX,findY] = queue.shift();
for(var moveI = 0;moveI<4;moveI++){
var dx = x + moveX[moveI];
var dy = y + moveY[moveI];
// 박스 밖을 나가가는지 체크 -> 안나간다면
if(dx>=0 && dy>=0 && dx<=4 && dy<=4){
// 맨허튼 거리에 2보다 작은 거리에 P가 있다면 return 0;
// 자기 자신이 아닌 P를 만단다면 0을 리턴 이때 거리는 2이하여야 한다.
if(arr[dy][dx]==="P" && count<=2 && dx!==findX && dy!==findY){
console.log("P발견", dx,dy,count,findX,findY);
return 0;
}
//현재 위치가 O이고 거리가 아직 1이하고 방문한 적이 없으면 그 다음으로 진행
if(arr[dy][dx]==="O" && count<=1 && visitArr[dy][dx] === false){
console.log("O발견", dx,dy,count,findX,findY);
queue.push([dx, dy,count+1,findX,findY])
visitArr[dy][dx] = true;
}
}
}
}
}
// 큐를 다 채크했을때 걸리는게 없다면 패스
return 1;
}
function solution(places) {
var answer = [];
for(var i = 0;i<places.length;i++){
answer.push(disCheck(places[i]));
}
return answer;
}
- 아래 논리를 5*5배열에 하나씩 순회하면서 아래 논리를 패스하면 1을 리턴하고 하나라도 걸린다면 0을 리턴한다.
- 만약 자기가 P라면 상하좌우에 P가 없어야 한다.
- 만약 자기가 O라면 상화좌우에 1개 이하여야 한다.
function disCheck(arr){
arr = arr.map((element)=>{
return element.split("");
})
var moveX = [1,-1,0,0];
var moveY = [0,0,1,-1];
for(var x = 0;x<5;x++){
for(var y = 0;y<5;y++){
// 자기 원소가 P일때 상하좌우에 P가 없어야 한다.
if(arr[y][x] === "P"){
for(var i =0;i<4;i++){
var dx = x+ moveX[i];
var dy = y + moveY[i];
if(dx>=0 && dy>=0 && dx<=4 && dy<=4){
if(arr[dy][dx]==="P"){
return 0;
}
}
}
}
if(arr[y][x]==="O"){
var count = 0;
for(var i =0;i<4;i++){
var dx = x+ moveX[i];
var dy = y + moveY[i];
if(dx>=0 && dy>=0 && dx<=4 && dy<=4){
if(arr[dy][dx]==="P"){
count++;
}
}
}
if(count>1){
return 0;
}
}
}
}
return 1;
}
function solution(places) {
var answer = [];
for(var i = 0;i<places.length;i++){
answer.push(disCheck(places[i]));
}
return answer;
}
우선 본인이 위에서 BFS로 시도했을때 틀린 이유는 visitArr이 다른 P를 탐색할때도 영향을 준다. 한마디로 새로운 P를 탐색할때 마다의 visitArr이 있었어야 한다. 만약 이러한 알고리즘을 원했다면 BFS보다 DFS 구현이 맞았다....
자신이 잘못되었다는 것을 깨닫고 좀 더 좋은 논리가 없을까 고민하다가 위와 같은 논리를 얻었고 시도보았는데, 다행히도 정답이 되었다.
BFS, DFS 등등 여러 알고리즘을 쓸때 자신이 정말 문제에 맞는 알고리즘을 쓰는지 체크해봐야 한다. 그렇지 않는다면 본인처럼 다 풀고 꺠달아서 문제를 다시 풀어야하는 번거러움이 있을 것이다.