will come true

[프로그래머스 / Level1] 비밀지도 (Java) 본문

Algorithm

[프로그래머스 / Level1] 비밀지도 (Java)

haehyun 2021. 11. 1. 18:17
728x90

문제

2018 KAKAO BLIND RECRUITMENT, https://programmers.co.kr/learn/courses/30/lessons/17681?language=java 

 

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

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

programmers.co.kr

#비트 연산(Bitwise Operation)

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

 

기존 코드 (성공)

class Solution {
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = new String[n];
        
        for(int i=0; i < n; i++){
            String row = String.format(String.format("%%%ds", n), Integer.toBinaryString(arr1[i] | arr2[i]));
            for(int j=0; j < n; j++){
            	answer[i] = row.replace('1', '#').replace('0', ' ');
            }
        }
        
        return answer;
    }
}

- 기존 코드가 생각보다 깔끔하게 짜져서 이번에는 기존 코드에 사용된 메서드들만 간단히 정리해보기로 했다.
- 프로그래머스 코테 연습에서 카카오문제가 나오면 괜시리 긴장됐는데, 그래도 Level1 문제는 사람이 풀 수 있는 난이도로 내주는 것 같다.

  1. 지도가 정사각형(n x n)이기 때문에 계산에 사용되는 모든 배열의 길이 n으로 같다.
    a. 지도의 가로줄(벽/공백)을 요소로 가지는 String 배열 answer의 길이 
    b. 지도1, 지도2의 가로줄(정수)을 요소로 가지는 int배열 arr1, arr2의 길이
    c. 지도1과 지도2를 겹쳐 얻은 이진수(=가로줄)의 길이
  2. 지도1과 지도2에서 각각 같은 자리의 칸(arr1[i], arr2[i])을 가져와 겹친다. 이때 겹친다는 것은 두 지도 중 하나에서라도 해당 칸이 벽(#)일 경우 벽(#)으로 처리한다는 것이다. = OR연산
  3. 두 지도에서 한줄을 겹친 결과를 Integer.toBinaryString() 함수를 통해 이진수로 변환 후, 앞자리를 공백으로 채운다. (어차피 다음 단계에서 0을 공백으로 대체할 것이기 때문에, 공백을 0으로 미리 전환해둘 필요는 없음. 즉, 공백==0)
  4. 이진수 문자열에서 1은 #은 1로, 0은 공백으로 대체한 문자열을 저장한다. 

 

학습 내용

비트연산 OR

public static void main(String[] args) {
	int a = 9;
	int b = 30;
	
	System.out.println(a + ":   " + Integer.toBinaryString(a));
	System.out.println(b + ": " + Integer.toBinaryString(b));
	System.out.println((a | b) + ": " + Integer.toBinaryString(a | b));		
}
9:   1001
30: 11110
31: 11111

두 수를 이진화했을 때 각 자릿수에 대해 하나라도 1이면 1로 변환한 이진수 문자열을 반환한다.
이때 정수를 이진화 했을때의 길이가 달라도 된다. (ex: 101, 11000 간의 비트연산 가능)

 

String.format() 문자열 형식화

String 문자열의 형식을 변경할 수 있다.

public static void main(String[] args) {
	int a = 8;
	int b = 1;
	String str = Integer.toBinaryString(a | b);
	
	System.out.println(String.format("%s_", str));
	System.out.println(String.format("%8s_", str));
	System.out.println(String.format("%-8s_", str));
	System.out.println(String.format("%.2s_", str));
	System.out.println(String.format("%8.2s_", str));
	System.out.println(String.format("%-8.2s_", str));
}
1001_
    1001_
1001    _
10_
      10_
10      _
  • %s : 문자열 그대로 유지
  • %8s : 문자열의 길이를 8로 맞추고 남은 자리는 공백으로 채우기 (오른쪽 정렬)
  • %-8s : 문자열의 길이를 8로 맞추고 남은 자리는 공백으로 채우기 (왼쪽 정렬)
  • %.2s : 문자열을 2자리 만큼 자르기
  • %8.2s : 문자열을 2자리 만큼 자른 뒤 길이를 8로 맞추고 남은 자리는 공백으로 채우기 (오른쪽 정렬)
  • %-8.2s : 문자열을 2자리 만큼 자른 뒤 길이를 8로 맞추고 남은 자리는 공백으로 채우기 (왼쪽 정렬)
  • 밑줄(_)은 출력 시 문자열의 위치 구분용 문자일 뿐 아무 의미 없음.

 

10진수를 2진수로 변환 시 앞자리 0 출력하기 (이진수 자릿수 맞추기)

String.format() 메서드를 사용해 Integer.toBinaryString() 로 구한 이진수 문자열을 원하는 길이로 출력할 수 있다.
이때 Integer.parseInt로 형변환해주는 이유는 정수 타입만 String.format()에서 %08d을 사용해 공백을 0으로 채우는 것이 가능하기 때문이다. 참고로 Integer.toBinaryString()의 반환값은 String타입.

public static void main(String[] args) {
	int a = 8;
	int b = 1;
	
	System.out.println(Integer.toBinaryString(a | b));
	System.out.println(String.format("%8s", Integer.toBinaryString(a | b)));
	System.out.println(String.format("%08d", Integer.parseInt(Integer.toBinaryString(a | b))));
    //System.out.println(String.format("%08s", Integer.toBinaryString(a | b))) 은 에러 발생
}
1001
    1001
00001001

 

String.Format 정수 자릿수 동적 할당

지금까지 "%8s"같이 고정자릿수를 기입해줬으나, 이 자릿수를 int변수 값에 따라 "%{n}s"같이 형식화되도록 할 수 있다.

public static String getFullBinary(int n, int num) {
	return String.format(String.format("%%0%dd", n), Integer.parseInt(Integer.toBinaryString(num)));
}

public static void main(String[] args) {
	int a = 8;
	int b = 1;
	int ab = a|b;
	System.out.println(getFullBinary(4, ab));
	System.out.println(getFullBinary(8, ab));
	System.out.println(getFullBinary(10, a|b));
}
1001
00001001
0000001001

 

위에서는 두 개의 String.format이 중첩되어 있는데, 2번째 String.format()의 반환값 문자열을 그대로 1번째 String.format() 메서드에 첫번째 매개변수(format)으로 사용하고 있다. 이를 두 구문으로 쪼개서 각 String.format()의 반환 문자열을 확인해보면 아래와 같다. (※ format에 %문자를 쓰고싶다면 %%와 같이 두번 연속으로 쓰면 된다)

public static void main(String[] args) {
	int a = 8;
	int b = 1;
	int ab = a|b;
	int n = 8;
	
	String s1 = String.format("%%0%dd", n);
	System.out.println(s1);
	String s2 = String.format(s1, Integer.parseInt(Integer.toBinaryString(ab)));
	System.out.println(s2);
}
%08d
00001001

 


[참고]

728x90
Comments