문제
칸토어 집합은 0과 1사이의 실수로 이루어진 집합으로, 구간 [0, 1]에서 시작해서 각 구간을 3등분하여 가운데 구간을 반복적으로 제외하는 방식으로 만든다.
전체 집합이 유한이라고 가정하고, 다음과 같은 과정을 통해서 칸토어 집합의 근사를 만들어보자.
1. -가 3N개 있는 문자열에서 시작한다.
2. 문자열을 3등분 한 뒤, 가운데 문자열을 공백으로 바꾼다. 이렇게 하면, 선(문자열) 2개가 남는다.
3. 이제 각 선(문자열)을 3등분 하고, 가운데 문자열을 공백으로 바꾼다. 이 과정은 모든 선의 길이가 1일때 까지 계속 한다.
예를 들어, N=3인 경우, 길이가 27인 문자열로 시작한다.
---------------------------
여기서 가운데 문자열을 공백으로 바꾼다.
--------- ---------
남은 두 선의 가운데 문자열을 공백으로 바꾼다.
--- --- --- ---
한번 더
- - - - - - - -
모든 선의 길이가 1이면 멈춘다. N이 주어졌을 때, 마지막 과정이 끝난 후 결과를 출력하는 프로그램을 작성하시오.
입력
입력을 여러 줄로 이루어져 있다. 각 줄에 N이 주어진다. 파일의 끝에서 입력을 멈춘다. N은 0보다 크거나 같고, 12보다 작거나 같은 정수이다.
출력
입력으로 주어진 N에 대해서, 해당하는 칸토어 집합의 근사를 출력한다.
예제 입력 1
0
1
3
2
예제 출력 1
-
- -
- - - - - - - -
- - - -
EOF(End Of File)
기존의 백준 문제는 항상 입력 문장의 개수를 파악할 수 있었는데, 이번 문제는 파일의 끝에서 입력을 멈추어야 해서 당황했다. 구글링해보니 다양한 방법이 있었는데, 그 중 EOF를 사용하는 방법으로 해결했다.
EOF란, End Of File의 줄임말로, 파일의 끝을 나타낸다, 이는 사용자가 더 이상 데이터를 읽을 수 없는 지점으로, 이 곳에 도달하게 되면 빈문자열이 출력으로 반환된다.
EOF를 사용하기 위해 무한으로 반복되는 while문 안에 try와 except를 사용하여 예외 처리를 진행할 것이다.
입력이 있을 땐 try문에 있는 코드들을 실행시키고, 입력이 없을 경우 break를 통해 while 문의 반복을 멈춘다.
풀이 1 - 메모리 초과
- 분할 정복(Divide and Conquer) 알고리즘의 재귀 방식을 이용하여 해결해보려고 했다.
// [BOJ] 4779. 칸토어 집합
import java.io.*;
// public
class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
int N = Integer.parseInt(br.readLine());
String answer = divideAndConquer(N);
System.out.println("answer : " + answer);
} catch (Exception e) {
break;
}
}
}
public static String divideAndConquer(int n) {
if (n == 0) return "-";
String blanks = "";
for (int i = 0 ; i < Math.pow(3, n - 1); i++) {
blanks += " ";
}
return divideAndConquer(n - 1) + blanks + divideAndConquer(n - 1);
}
}
해당 풀이는 메모리 초과가 났는데, 재귀를 들어가면서 반환되는 문자열들의 길이가 3^12 = 531441, 3^11 = 177147, ... 로 메모리를 많이 사용하기 때문인 것으로 추측된다.
풀이 2 - StringBuilder 이용
Java의 String의 경우 특정 인덱스에 위치한 원소값을 수정할 수 없지만 StringBuilder를 사용하면 setCharAt 메소드를 이용하여 수정이 가능하다고 한다. 때문에 매번 새로운 객체를 생성하는 String을 사용할 때보다 메모리를 크게 줄일 수 있다.
// [BOJ] 4779. 칸토어 집합
import java.io.*;
// public
public class Main {
public static StringBuilder sb;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
int N = Integer.parseInt(br.readLine());
sb = new StringBuilder();
for (int i = 0; i < (int) Math.pow(3, N); i++) {
sb.append("-");
}
divideAndConquer(0, (int) Math.pow(3, N));
System.out.println(sb);
} catch (Exception e) {
break;
}
}
}
public static void divideAndConquer(int start, int size) {
if (size == 1) return;
int newSize = size / 3;
for (int i = start + newSize; i < start + 2 * newSize; i++) {
sb.setCharAt(i, ' ');
}
divideAndConquer(start, newSize);
divideAndConquer(start + 2 * newSize, newSize);
}
}
'Algorithm' 카테고리의 다른 글
[LeetCode] 2695. Array Wrapper (0) | 2024.01.31 |
---|---|
[LeetCode] 2677. Chunk Array (0) | 2024.01.31 |
[SWEA] 1230. 암호문3 (1) | 2024.01.29 |
[SWEA] 10726. 이진수 표현 (0) | 2024.01.29 |
[SWEA] 1288. 새로운 불면증 치료법 (0) | 2024.01.29 |