jusung-c
으 하기싫어
jusung-c
  • 공부 기록 (96)
    • Spring (42)
      • Spring 기초 이론 (8)
      • Spring 핵심 원리 - 기본 (9)
      • Blog 만들기 with SpringBoot (25)
    • JAVA (7)
      • Java 문법 (2)
      • 객체지향의 사실과 오해 (5)
    • Algorithm (47)
      • 자료구조 (3)
      • 완전탐색 (22)
      • 정렬 (4)
      • 이분탐색 (12)
      • 투 포인터 (4)
hELLO · Designed By 정상우.
jusung-c

으 하기싫어

BOJ 2470 - 두 용액 (투 포인터)
Algorithm/투 포인터

BOJ 2470 - 두 용액 (투 포인터)

2022. 6. 9. 20:39

https://www.acmicpc.net/problem/2470

 

2470번: 두 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -1,000,000,000 이상 1,000,00

www.acmicpc.net

 

- 서로 다른 두 용액을 더해서 합이 최대한 0에 가깝게 만드는 문제

- 산성 용액 (1 ~ 10억)

- 알칼리성 용액 (-10억 ~ -1)

 

 

아이디어

기존의 이분탐색 풀이법을 생각해보면 먼저 용액들을 정렬을 해준 후 이분탐색을 통해 답을 구했었다. 

 

새로운 관점으로 투 포인터를 활용해서 풀이를 해보자

 

포인터 L과 R을 사용한다. L은 제일 작은 원소(최소)를 가리키고, R은 제일 큰 원소(최대)를 가리키도록 한다. 

 

  • 최소와 최대를 더했을 때 0보다 작은 경우
    • 최소 용액 입장에선 최대 용액이랑 더해도 음수라는 뜻이므로 최선의 짝을 찾은 것이다. 따라서 삭제해주고 더 이상 고려하지 않는다.

 

  • 최소와 최대를 더했을 때 0보다 큰 경우 
    • 최대 용액 입장에서 최소 용액이랑 더해도 양수라는 뜻이므로 최선의 짝을 찾은 것이다. 따라서 삭제해주고 더 이상 고려하지 않는다. 

 

예를 들어 용액이 -99 -2 -1 4 98인 경우를 생각해보자

  • L + R < 0  
    • L이 최선책을 만났으므로 L++로 제외

 

  • L + R > 0
    • R이 최선책을 만났으므로 R--로 제외

이런 과정을 반복해서 최선책을 만날때마다 0과 가까운 값으로 갱신해주기만 하면 답을 구할 수 있다.

 

시간 복잡도

1. L과 R을 빠르게 찾기 위해 정렬을 해준다. -> O(N logN)

2. 원소가 1개가 될 때까지 반복해야 한다. -> N번 반복

3. 따라서 총 O(N logN)의 시간이 걸린다. 

 

 

구현

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static int N;
    static int[] list;

    static void init() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        N = Integer.parseInt(br.readLine());

        list = new int[N + 1];
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        for (int i = 1; i <= N; i++) {
            list[i] = Integer.parseInt(st.nextToken());
        }
    }

    static void pro() throws IOException {
        // list 정렬
        Arrays.sort(list, 1, N + 1);

        // 투 포인터
        int L = 1;
        int R = N;
        int r1 = 0;
        int r2 = 0;
        int ans = Integer.MAX_VALUE;

        // L == R의 경우는 한 용액만 남는 경우임
        while (L < R) {
            int sum = list[L] + list[R];

            // ans, r1, r2 갱신
            if (Math.abs(sum) < ans) {
                // 비교하기 쉽도록 절댓값으로 갱신
                ans = Math.abs(sum);
                r1 = list[L];
                r2 = list[R];
            }

            // 최소와 최대를 더했을 때 0보다 큰 경우
            if (sum > 0) {
                R--;

            // 최소와 최대를 더했을 때 0보다 작은 경우
            } else {
                L++;
            }
        }

        bw.write(r1+" "+r2);
    }

    public static void main(String[] args) throws IOException {
        init();

        pro();

        bw.close();
    }

}

 

저작자표시 비영리 변경금지 (새창열림)

'Algorithm > 투 포인터' 카테고리의 다른 글

BOJ 2230 - 수 고르기  (0) 2022.06.07
BOJ 15565 - 귀여운 라이언  (0) 2022.05.19
[Algorithm] Two Pointers  (0) 2022.05.16
    'Algorithm/투 포인터' 카테고리의 다른 글
    • BOJ 2230 - 수 고르기
    • BOJ 15565 - 귀여운 라이언
    • [Algorithm] Two Pointers
    jusung-c
    jusung-c

    티스토리툴바