코딩테스트/백준
[백준] 1992번 - 쿼드트리 풀이 및 코드 분석 (Java)
현걸
2025. 2. 27. 10:55
1. 문제 분석
쿼드트리는 흑백 영상 압축 방식 중 하나로, 2차원 배열을 네 개의 구역으로 나누어 표현하는 방법.
주어진 영상이 모두 같은 값(0 또는 1)으로 이루어져 있다면 해당 숫자로 압축되지만, 0과 1이 섞여 있다면 네 개의 부분으로 나눈 뒤 각 부분을 다시 압축하는 방식.
이 문제는 재귀적인 방식으로 2차원 배열을 압축하여 출력하는 것이 핵심.
입력 조건
- 첫 번째 줄: 영상의 크기 N (1 ≤ N ≤ 64), 항상 2의 제곱수로 주어짐
- 두 번째 줄부터: N개의 길이가 N인 문자열 (0 또는 1)
출력 조건
- 압축된 쿼드트리 결과를 출력
예를 들어, 아래와 같은 입력이 주어진다면:
8
11110000
11110000
00001111
00001111
11110000
11110000
00001111
00001111
출력은 다음과 같이 됩니다:
((1100)(1100)(0011)(0011))
2. 해결 방법
분할 정복 (Divide and Conquer)와 재귀 사용
- 기저 조건
- 주어진 영역이 1x1 크기일 경우, 해당 숫자를 출력.
- 주어진 영역이 모두 같은 숫자(0 또는 1)로 이루어져 있다면, 해당 숫자로 압축.
- 재귀적으로 4개의 영역으로 나누어 탐색
- 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래 영역을 재귀적으로 탐색.
- 4개의 영역을 다시 같은 방식으로 처리하며 압축된 결과를 괄호로 묶어서 표현.
- 압축된 결과 저장 및 출력
StringBuilder
를 사용하여 문자열을 효율적으로 저장하고 출력.
3. 코드 구현
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
static int N;
static int[][] board;
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
board = new int[N][N];
for (int r = 0; r < N; r++) {
String[] arr = br.readLine().split("");
for (int c = 0; c < N; c++) {
board[r][c] = Integer.parseInt(arr[c]);
}
}
compress(0, N, 0, N);
System.out.println(sb);
}
private static void compress(int sr, int er, int sc, int ec) {
if (isUniform(sr, er, sc, ec)) {
sb.append(board[sr][sc]);
return;
}
sb.append("(");
int midR = (sr + er) / 2;
int midC = (sc + ec) / 2;
compress(sr, midR, sc, midC); // 1사분면
compress(sr, midR, midC, ec); // 2사분면
compress(midR, er, sc, midC); // 3사분면
compress(midR, er, midC, ec); // 4사분면
sb.append(")");
}
private static boolean isUniform(int sr, int er, int sc, int ec) {
int value = board[sr][sc];
for (int r = sr; r < er; r++) {
for (int c = sc; c < ec; c++) {
if (board[r][c] != value) {
return false;
}
}
}
return true;
}
}
4. 코드 분석
시간 복잡도
- 재귀 호출에서 각 단계마다 4개의 부분으로 나누어 호출하므로, O(N^2) 복잡도를 가짐.
- 최악의 경우 2^6 x 2^6 = 64 x 64 = 4096번의 연산이 필요하지만, 압축이 잘 이루어진다면 더 적은 연산으로 해결 가능.
메모리 사용 최적화
StringBuilder
를 사용하여 문자열 연산을 최적화.BufferedReader
를 사용하여 입력을 빠르게 처리.
주요 함수 설명
compress(int sr, int er, int sc, int ec)
- 현재 영역이 모두 같은 값인지 검사 후, 그렇다면 숫자 출력.
- 아니라면 4개의 영역으로 나누고 재귀적으로 처리.
isUniform(int sr, int er, int sc, int ec)
- 주어진 영역이 모두 같은 값인지 검사.
5. 개선할 점 및 대체 방법
개선할 점
- 압축 검사 최적화
- 현재
isUniform
함수에서 2중 for문을 사용하여 모든 값을 검사하지만, 이 과정을 최적화할 방법을 고려 가능. - 예를 들어, 합계를 미리 계산해두면 비교 연산을 줄일 수 있음.
- 현재
- 메모리 사용 최적화
board
배열을char[][]
로 선언하면, 불필요한int
변환을 줄일 수 있음.
대체 방법
- DFS(깊이 우선 탐색) 방식 적용 가능
- 쿼드트리는 본질적으로 DFS와 유사한 구조를 가짐.
- 반복문을 활용한 비재귀적 방식으로 구현할 수도 있음.