알고리즘/백준

[백준][C++] 9024: 두 수의 합

KANTAM 2023. 10. 31. 15:44

문제

풀이

이분 탐색을 사용한다.

  • 모든 수열을 탐색하면 O(n^2)으로 시간초과이다. 
  • 각 수열의 수 마다, 다른 수와의 합과 K와의 차이의 최솟값을 찾는다.
  • 최솟값을 찾을 때, 이분 탐색으로 최솟값을 찾고, K와의 차이에 따라 범위를 조절한다.
  • 해당 최솟값이 현재 나온 최솟값과 같다면 answer를 증가하고 더 작다면 갱신한다.

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>

using namespace std;

vector<int> nums;

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(nullptr);

    int t;
    cin >> t;

    while (t--)
    {
        int n, K;
        cin >> n >> K;

        for (int i = 0; i < n; ++i)
        {
            int temp;
            cin >> temp;
            nums.push_back(temp);
        }

        sort(nums.begin(), nums.end());

        // 두 수의 합과 K의 차의 절대값의 최솟값인 mini
        // mini인 경우의 조합의 수 answer
        int mini = INT_MAX;
        int answer = 1;

        // 수열의 처음부터 끝까지 검사
        // K와의 차이에 따라 범위를 달리하며 이분 탐색
        // i에서의 다른 수와의 합의 차이 중 가장 작은 값이 current에 들어간다.
        for (int i = 0; i < n; ++i)
        {
            int current = INT_MAX;

            // 서로 다른 수의 합이므로 i + 1에서부터 검사한다.
            int start = i + 1;
            int end = n - 1;
            while (start <= end)
            {
                int mid = (start + end) / 2;

                // i와 mid에서의 합과 K와의 차이 중 가장 작은 값인 current
                current = min(current, abs(K - (nums[i] + nums[mid])));

                // i와 mid에서의 합과 K와의 차이에 따라 범위 조절
                if (nums[i] + nums[mid] >= K)
                {
                    end = mid - 1;
                }
                else
                {
                    start = mid + 1;
                }
            }

            // i와 mid에서의 합과 K와의 차이가 mini와 같다면 answer 증가
            if (current == mini)
            {
                answer++;
            }
            // 더 작다면 mini를 갱신
            else if (current < mini)
            {
                mini = current;
                answer = 1;
            }
        }

        cout << answer << '\n';

        nums.clear();
    }

    return 0;
}