프로그래머스

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

빙수빈수 2021. 7. 19. 14:13

https://programmers.co.kr/learn/courses/30/lessons/17681

 

코딩테스트 연습 - [1차] 비밀지도

비밀지도 네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다

programmers.co.kr

[문제]

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

 

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

 

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

 

[입력 조건]

입력으로 지도의 한 변 크기 n 과 2개의 정수 배열 arr1, arr2가 들어온다.

  • 1 ≦ n ≦ 16
  • arr1, arr2는 길이 n인 정수 배열로 주어진다.
  • 정수 배열의 각 원소 x를 이진수로 변환했을 때의 길이는 n 이하이다. 즉, 0 ≦ x ≦ 2^(n - 1)을 만족한다.

 

[코드]

class Solution {
   public String[] solution(int n, int[] arr1, int[] arr2) {
		String[] answer=new String[n];
        
		/*
		 * 두 개의 비밀지도 각 줄마다 10진수의 값을 2진수로 변환 후
		 * 두 2진수의 각 자리를 비교하여 공백 또는 #을 저장한다.
		 * 이러한 과정을 주어진 비밀지도의 길이인 n만큼 반복한다.  
		 */
        for(int i=0;i<n;i++) {
        	// 각 배열의 10진수 값을 2진수로 변환한다.
        	int[] arr1Binary=makeBinary(n,arr1[i]);
            int[] arr2Binary=makeBinary(n,arr2[i]);
            String str="";
            
            /* 
             * 2진수로 변환한 자릿수의 값이 모두 0일 경우에만 공백 저장
             * 둘 중 하나의 값이라도 1일 경우에는 '#' 저장
             */
            for(int j=0;j<arr1Binary.length;j++) {
            	if(arr1Binary[j]==0&&arr2Binary[j]==0) {
            		str+=" ";
            	}
            		
            	else 
            		str+="#";
            }
            // 한 줄이 처리가 끝나면 결과 값 answer 배열에 저장
            answer[i]=str;
        }
        return answer;
    }
	
	// 10진수를 2진수로 변환하는 함수
	public int[] makeBinary(int n,int num) {
		int[] result=new int[n];
		int number=num;
		
		for(int i=n-1;i>=0;i--) {
			result[i]=number%2;
			number/=2;
		}
		return result;
	}
}

 

[고찰]

 문제를 다 풀고난 후 좀 더 효율적으로 코드를 구성하는 방법이 있지는 않을까 생각해 다른 사람들의 포스팅을 열람해봤다. 그 결과 이번 문제는 라이브러리로 제공하는 함수를 사용하면 더 쉽게 해결할 수 있다는 것을 알았다. 아래 코드가 해당 부분이다.

class Solution {
       
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = new String[n]; 
                
        for(int i =0;i<n;i++){
            // arr1과 arr2의 원소들을 이진수로 바꾼 뒤, or 비트 논리연산 수행.
            String str=Integer.toBinaryString(arr1[i] | arr2[i]);
            // 5자리의 문자열 형태로 포맷변경, 5자리가 안되는 이진수의 나머지는 공백으로 채운다.
            str = String.format("%"+n+"s",str);
            // 1->#, 0->공백 으로 바꾼다.
            str = str.replaceAll("1" , "#");
            str = str.replaceAll("0" , " ");
            // 한 줄 완성.
            answer[i] = str;
        }
        return answer;
    }
}

 위 코드는 10진수를 2진수로 변경해주는 Integer.toBinartString() 함수를 사용하여 풀이한 방법이다. 또한 2진법으로 바꾸는 동시에 or 비트 논리연산을 수행하여 각 자릿수가 0인지 1인지 판별해야 하는 if문 또한 필요하지 않아졌다. 이런 방법을 사용하면 따로 변경 함수와 판별문을 만들어주지 않아도 돼 훨씬 코드가 간결해 진 것을 확인할 수 있다.

하지만 위 함수를 몰랐다 하더라도 직접 구현하는 방법으로 풀이하여 충분히 정답 처리를 받을 수 있다.