개발자/알고리즘
[코딩테스트-SWEA] 3차원 농부 - Java 이진 탐색 문제 풀이
naheesu
2025. 4. 20. 17:28
안녕하세요, 오늘은 삼성 SW Expert Academy의 "3차원 농부" 문제를 Java로 풀이한 내용을 공유드립니다. 이 문제는 대용량 데이터를 다루는 상황에서 이진 탐색을 활용해야 하는 전형적인 문제입니다.
📚 목차
- 문제 개요
- 문제 조건 요약
- 핵심 아이디어
- 알고리즘 설계
- 자바 코드
- 예제 입력/출력
- 시간 복잡도
- 마무리 정리
1. 문제 개요
농부 지민이는 특이하게도 소와 말을 3차원 공간에서 기릅니다. 모든 소는 (c1, 0, z) 위치에, 모든 말은 (c2, 0, z) 위치에 존재합니다.
소와 말 사이의 맨해튼 거리가 가까우면 이산화탄소가 많이 발생하므로, 지민이는 가장 가까운 소-말 쌍의 거리와 그러한 쌍의 개수를 알고 싶어합니다.
2. 문제 조건 요약
- 소와 말 각각 최대 50만 마리 (N, M ≤ 500,000)
- 위치는 3차원: (x, 0, z)
- 거리 계산: |x1 - x2| + |y1 - y2| + |z1 - z2|
- 모든 소는 x = c1, 말은 x = c2 → 결국 |c1 - c2|는 고정값
3. 핵심 아이디어
맨해튼 거리의 x축 차이는 고정되어 있으므로, z값 차이만 고려하면 된다!
- 거리 = |c1 - c2| + |z_cow - z_horse|
- |c1 - c2|는 고정 → |z_cow - z_horse|가 최소인 경우를 찾자!
- 말의 z좌표 하나마다 이진 탐색으로 소 배열에서 가장 가까운 값을 찾으면, 전체 최소값을 빠르게 구할 수 있다.
4. 알고리즘 설계
- 소의 z좌표를 오름차순 정렬
- 각 말의 z좌표에 대해 이진 탐색 수행
- 가장 가까운 소의 z좌표를 찾아 |z_cow - z_horse| 계산
- 최소 거리라면 갱신, 같으면 개수 증가
- 마지막 출력: |c1 - c2| + minDistance, count
5. 자바 코드
import java.io.*;
import java.util.*;
class Solution {
public static void main(String args[]) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int test_case = Integer.parseInt(in.readLine());
for(int t = 0; t<test_case; t++ ){
StringTokenizer st = new StringTokenizer(in.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int[] cow = new int[N];
st = new StringTokenizer(in.readLine());
int c1 = Integer.parseInt(st.nextToken());
int c2 = Integer.parseInt(st.nextToken());
st = new StringTokenizer(in.readLine());
for(int i = 0; i<N; i++){
cow[i] = Integer.parseInt(st.nextToken());
}
Arrays.sort(cow);
int minValue = Integer.MAX_VALUE;
int minCount = 0;
st = new StringTokenizer(in.readLine());
for(int i = 0; i<M; i++ ){
int horse = Integer.parseInt(st.nextToken());
int start = 0;
int end = N-1;
while(start <= end){
int mid = (start + end) / 2;
int dist = Math.abs(cow[mid] - horse);
if (dist < minValue) {
minValue = dist;
minCount = 1;
} else if (dist == minValue) {
minCount++;
}
if (cow[mid] < horse) {
start = mid + 1;
} else {
end = mid - 1;
}
}
}
int dx = Math.abs(c1 - c2);
bw.write("#" + (t+1) + " " + (dx + minValue) + " " + minCount + "\n");
}
bw.flush();
bw.close();
}
}
6. 예제 입력/출력
✅ 입력
1
3 3
0 2
1 2 3
5 6 7
✅ 출력
#1 4 1
- x축 거리: |0 - 2| = 2
- z좌표 최소 거리: |3 - 5| = 2
- 총 거리: 2 + 2 = 4
- 그런 쌍은 1개
7. 시간 복잡도
- 소 정렬: O(N log N)
- 말에 대해 이진 탐색: O(M log N)
- 전체: O(N log N + M log N) → 최대 2000만 연산으로 시간 내 통과 가능
8. 마무리 정리
이 문제는 단순한 완전 탐색으로는 시간 초과가 발생합니다. 핵심은 다음 두 가지입니다:
- 맨해튼 거리 계산에서 고정값을 분리
- 이진 탐색으로 거리 계산 최적화
대용량 데이터 처리 문제에서 자주 등장하는 패턴이므로, 잘 익혀두시면 좋습니다!
도움이 되셨다면 공감❤️과 댓글📝 부탁드립니다!
더 많은 코딩 테스트 풀이가 궁금하다면 [블로그 구독] 해주세요 😊