코딩 테스트

[프로그래머스 Level 1] 비밀지도

y_flm 2025. 4. 29. 16:52
반응형
문제:
네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다.
그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다.
다행히 지도 암호를 해독할 방법을 적어놓은 메모도 함께 발견했다.

  1. 지도는 한 변의 길이가 n인 정사각형 배열 형태로, 각 칸은 "공백"(" ") 또는 "벽"("#") 두 종류로 이루어져 있다.
  2. 전체 지도는 두 장의 지도를 겹쳐서 얻을 수 있다. 각각 "지도 1"과 "지도 2"라고 하자.
      지도 1 또는 지도 2 중 어느 하나라도 벽인 부분은 전체 지도에서도 벽이다.
      지도 1과 지도 2에서 모두 공백인 부분은 전체 지도에서도 공백이다.
  3. "지도 1"과 "지도 2"는 각각 정수 배열로 암호화되어 있다.
  4. 암호화된 배열은 지도의 각 가로줄에서 공백 부분을 0, 벽 부분을 1로 부호화했을 때 얻은 이진수에 해당하는 값의 배열이다.

네오가 프로도의 비상금을 손에 넣을 수 있도록, 비밀지도의 암호를 해독하는 작업을 도와줄 프로그램을 작성하라.

 

문제 풀어보기: https://school.programmers.co.kr/learn/courses/30/lessons/17681

 

풀이보기
더보기
function solution(n, arr1, arr2) {
    let map1 = [];
    let map2 = [];
    let allMap = [];
    
    for(let i = 0; i < arr1.length; i++) {
        map1.push(arr1[i].toString(2));
        map2.push(arr2[i].toString(2));
        
        map1[i] = '0'.repeat(n - map1[i].length) + map1[i];
        map2[i] = '0'.repeat(n - map2[i].length) + map2[i];
        
        map1[i] = map1[i].replace(/0/g, ' ').replace(/1/g, '#');
        map2[i] = map2[i].replace(/0/g, ' ').replace(/1/g, '#');
    }
    
    for(let i = 0; i < map1.length; i++) {
        allMap.push([]);
        
        for(let j = 0; j < map1[i].length; j++) {
            if(map1[i][j] === ' ' && map2[i][j] === ' ') {
                allMap[i].push(' ');
            } else {
                allMap[i].push('#');
            }
        }
        
        allMap[i] = allMap[i].join('');
    }
    
    return allMap;
}

ㅎㅎ.. 처음에는 단순히 문제 해결에만 집중해서 풀었더니 이런 코드가 나왔다.

 

문제 그대로 먼저 arr을 각각 2진수로 바꾼후 map에 넣어주고, 

그 다음 n에 맞게 길이를 0으로 채워준 뒤 0 ,1을 각각 공백과 #으로 바꿔주었다.

그리고 각 map을 기준으로 하나씩 비교하며 둘 다 공백일 때만 공백을 넣어주고 그 외에는 #을 넣어주었다.

마지막으로 allMap[i]를 문자열로 바꿔주고 allMap을 리턴해주면 끝이다.

 

물론 정답이긴 하지만 굉장히 반복되는 코드도 많고 마음에 들지 않았다.

근데 도저히 어떻게 풀지 생각이 안나서 여러 메서드를 찾아보았다.

그러던 중에 알게 된 padStart가 repeat 대신 쓸 수 있는 간단한 메서드 였다.

padStart는 padStart(원하는 문자열 길이, 채울 문자열) 이렇게 사용하며 간단하다.

그럼 코드가 아래와 같이 바뀌게 된다.

// 변경 전
for(let i = 0; i < arr1.length; i++) {
        map1.push(arr1[i].toString(2));
        map2.push(arr2[i].toString(2));
        
        map1[i] = '0'.repeat(n - map1[i].length) + map1[i];
        map2[i] = '0'.repeat(n - map2[i].length) + map2[i];
        
        map1[i] = map1[i].replace(/0/g, ' ').replace(/1/g, '#');
        map2[i] = map2[i].replace(/0/g, ' ').replace(/1/g, '#');
    }

// 변경 후
for(let i = 0; i < arr1.length; i++) {
        map1.push(arr1[i].toString(2).padStart(n, '0'));
        map2.push(arr2[i].toString(2).padStart(n, '0'));
        
        map1[i] = map1[i].replace(/0/g, ' ').replace(/1/g, '#');
        map2[i] = map2[i].replace(/0/g, ' ').replace(/1/g, '#');
    }

 

간결해지긴 했지만 지피티의 도움을 얻어 더 효율적인 코드를 얻을 수 있었다 ㅎㅎ .. 

function solution(n, arr1, arr2) {
    let allMap = [];
    
    for(let i = 0; i < n; i++) {
        let binary = (arr1[i] | arr2[i]).toString(2).padStart(n, '0');
        let row = binary.replace(/1/g, '#').replace(/0/g, ' ');
        allMap.push(row);
    }
    
    return allMap;
}

비교도 안되게 짧아진 코드 ㅎㅎ .. 

그 이유는 (arr1[i] | arr2[i])를 통해서 더 간결해진건데 두 숫자의 비트 연산자를 수행하여 값이 나오게되는 것이다.

(예: 9 | 14 → 1001 | 1110 = 1111 → 10진수로 15)

그렇기 때문에 이전과 같이 map1, map2를 따로 선언해서 계산한 뒤 푸쉬해줄 필요가 없는 것이다.

먼저 두 arr을 연산해주기 때문에 마지막에 이 값을 #과 공백으로 바꿔준 뒤 allMap에 푸쉬하면 끝이다!

 

반응형