[백준] 2470 : 두 용액 - Java

이지연·2026년 1월 4일
post-thumbnail

문제 요약

산성(-)과 염기성(+) 용액이 섞여 있다.
두 용액을 섞었을 때, 특성값의 합이 0에 가장 가까운 값을 만드는 두 용액의 특성값을 출력하는 문제다.

즉,

  • 배열 arr에서 두 수를 선택해
  • |arr[i] + arr[j]| 의 최소값을 만들고, 그때의 두 수를 출력한다.

핵심 아이디어

이 문제는 단순히 “합이 특정 값”이 아니라 “합이 0에 가장 가까운 값”을 찾아야 하므로,
기존 두 수의 합과는 약간 다른 접근이 필요하다.

핵심은 정렬 후 투 포인터 + 최소값 추적이다:

  1. 배열을 정렬한다.
  2. 양 끝 포인터(start, end)로 합을 계산.
  3. 절댓값 합이 현재 최소값보다 작으면 갱신.
  4. 합이 0보다 크면 end--, 0보다 작거나 같으면 start++

알고리즘 핵심 로직

1. 배열 정렬 (오름차순)
2. start = 0, end = n-1, minValue = 무한대
3. while start < end:
   value = |arr[start] + arr[end]|
   
   if value < minValue:
       minValue = value
       result = {arr[start], arr[end]}
   
   if arr[start] + arr[end] > 0:
       end--
   else:
       start++
   if value == 0: break  // 완벽한 0 발견

핵심: 합의 절댓값을 최소화하는 쌍을 추적한다.


전체 코드 (제출용)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int n = Integer.parseInt(br.readLine());
        StringTokenizer st = new StringTokenizer(br.readLine());
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        Arrays.sort(arr);
        int startIdx = 0;
        int endIdx = n - 1;
        int minValue = Integer.MAX_VALUE;
        int[] temp = new int[2];

        while (startIdx < endIdx) {
            int value = Math.abs(arr[startIdx] + arr[endIdx]);

            if (minValue > value) {
                minValue = value;
                temp[0] = arr[startIdx];
                temp[1] = arr[endIdx];
            }

            if (arr[startIdx] + arr[endIdx] > 0) {
                endIdx--;
            } else {
                startIdx++;
            }
            if (value == 0) break;
        }

        System.out.println(temp[0] + " " + temp[1]);
    }
}

예제 시뮬레이션

입력: [-2, 4, -99, -1, 98]
정렬 후: [-99, -2, -1, 4, 98]

startend
-9998-111start++
-2989696-end--
-2422-end--
-2-1-33-start++

최종 결과: -2 4 (합 = 2, |합| = 2)


핵심 포인트 정리

  • 절댓값 최소화Math.abs(합) 비교 후 최소값 추적
  • 합 > 0 이면 end--, 합 ≤ 0 이면 start++
  • 0 발견 시 즉시 종료로 최적화 가능
  • 시간 복잡도: (O(n \log n + n))
profile
Eazy하게

0개의 댓글