[알고리즘 풀이 분석] BOJ 2470 두 용액

nnnyeong·2021년 9월 23일
0

알고리즘 풀이분석

목록 보기
64/101

오늘 풀어본 문제는 BOJ 2470 두 용액 이다! 골드 5 단계의 문제인데 이분 탐색을 연습하려고 시작했는데 막상 풀이는 투포인터로 풀게 되었다. 그래서 정답 맞춘 이후에 이분 탐색 방법도 찾아서 다시 한번 풀어보았다.




BOJ 2470 두 용액

KOI 부설 과학연구소에서는 많은 종류의 산성 용액과 알칼리성 용액을 보유하고 있다. 각 용액에는 그 용액의 특성을 나타내는 하나의 정수가 주어져있다. 산성 용액의 특성값은 1부터 1,000,000,000까지의 양의 정수로 나타내고, 알칼리성 용액의 특성값은 -1부터 -1,000,000,000까지의 음의 정수로 나타낸다.

같은 양의 두 용액을 혼합한 용액의 특성값은 혼합에 사용된 각 용액의 특성값의 합으로 정의한다. 이 연구소에서는 같은 양의 두 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들려고 한다.

예를 들어, 주어진 용액들의 특성값이 [-2, 4, -99, -1, 98]인 경우에는 특성값이 -99인 용액과 특성값이 98인 용액을 혼합하면 특성값이 -1인 용액을 만들 수 있고, 이 용액이 특성값이 0에 가장 가까운 용액이다. 참고로, 두 종류의 알칼리성 용액만으로나 혹은 두 종류의 산성 용액만으로 특성값이 0에 가장 가까운 혼합 용액을 만드는 경우도 존재할 수 있다.

산성 용액과 알칼리성 용액의 특성값이 주어졌을 때, 이 중 두 개의 서로 다른 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액을 찾는 프로그램을 작성하시오.




입출력

[입력]

  • 첫째 줄에는 전체 용액의 수 N이 입력된다.
  • N은 2 이상 100,000 이하이다.
  • 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다.
  • 이 수들은 모두 -1,000,000,000 이상 1,000,000,000 이하이다.
  • N개의 용액들의 특성값은 모두 다르고, 산성 용액만으로나 알칼리성 용액만으로 입력이 주어지는 경우도 있을 수 있다.

[출력]

  • 첫째 줄에 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액의 특성값을 출력한다.
  • 출력해야 하는 두 용액은 특성값의 오름차순으로 출력한다.
  • 특성값이 0에 가장 가까운 용액을 만들어내는 경우가 두 개 이상일 경우에는 그 중 아무것이나 하나를 출력한다.



나의 풀이

Two Pointer

문제에서 주어진 N 의 값은 최대 100,000 이하이다. 투포인터를 사용하면 O(N) 으로 풀 수 있겠다 싶었다.

먼저 주어진 정수들을 오름 차순으로 정렬 시킨 뒤 두 포인터 변수 left right 는 각각 0, N-1 에서 시작한다. 두 포인터가 가리키고 있는 변수를 더한 값이 0보다 작다면 left를 증가, 0보다 크다면 right를 감소 시킨다.

탐색 과정에서 두 수의 합이 최소라면 해당 시점에 두 포인터가 가리키는 변수를 차례대로 기록한다. left<right 가 유지되는 선에서 탐색을 진행한다.

left<right 조건이 유지되어야 하므로 N개의 정수를 한번씩만 탐색해서 정답을 구할 수 있었다!

하지만 동일한 방법으로 swift 로 풀어보았지만 시간초과가 발생했다 ㅜ 왜그런거지,, swift 로 한다면 log N 에 끝내야 한다는 소리인가,,?


이분 탐색 이용 방법은 잘 생각이 나지 않아 [BinarySearch] BOJ 2470 두 용액 포스팅을 참고하였다.

투포인터 사용시와 동일하게 주어진 숫자들을 오름차순으로 정렬한 뒤 i = 0~N-1 번째 정수를 기준으로 해당 숫자에 더해서 가장 최소의 절댓값을 갖는 수를 찾는 방식이다.

두 변수 left, right 는 각각 i+1, n-1 에서 시작하고 mid = (left+right)/2 가 가리키는 정수와 i번째 정수의 합이 최소가 되는 지점을 찾아 나간다.

N개의 변수에 대해서 진행되고 각 변수마다 최적의 짝을 찾는 과정은 logN 의 시간을 가질테니 O(N log N)의 시간복잡도를 가지는 것 같다.




코드

Two Pointer

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

pair<long, long> solution(vector<long> numbers){
    pair<long, long> answer;

    sort(numbers.begin(), numbers.end());
    long  min = 2147483647;
    int left = 0, right = numbers.size()-1;

    while (left<right){
        int sum = numbers[left] + numbers[right];

        if (min > abs(sum)){
            min = abs(sum);
            answer.first = numbers[left];
            answer.second = numbers[right];
        }

        if (sum < 0) left++;
        else right--;

    }

    return answer;
}


int main() {
    int N;
    cin>>N;

    vector<long> numbers(N);
    for (int i = 0; i < N; ++i) {
        cin>>numbers[i];
    }

    pair<long, long> answer = solution(numbers);

    cout<<answer.first<<' '<<answer.second;

    return 0;
}

Binary Search

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

pair<long, long> solution(vector<long> numbers){
    pair<long, long> answer;
    sort(numbers.begin(), numbers.end());
    long  min = 2147483647;

    for (int i = 0; i < numbers.size(); ++i) {
        int left = i+1, right = numbers.size()-1;

        while (left<=right){
            int mid = (left+right)/2;
            int sum = numbers[i] + numbers[mid];

            if (abs(sum) < min){
                min = abs(sum);
                answer.first = numbers[i];
                answer.second = numbers[mid];
            }

            if (sum<0) left = mid+1;
            else right = mid-1;
        }

    }

    return answer;
}


int main() {
    int N;
    cin>>N;

    vector<long> numbers(N);
    for (int i = 0; i < N; ++i) {
        cin>>numbers[i];
    }

    pair<long, long> answer = solution(numbers);

    cout<<answer.first<<' '<<answer.second;

    return 0;
}
profile
주니어 개발자까지 ☄️☄️

0개의 댓글