ALGORITHM NOTE1

BOJ 3273 - 두 수의 합

어떤 두 수가 조건을 만족할까?

#algorithm#boj#silver#sorting#two-pointers
아카이브로 돌아가기

문제 링크

문제

nn개의 서로 다른 양의 정수 a1a_1, a2a_2, ..., ana_n으로 이루어진 수열이 있다. aia_i의 값은 1보다 크거나 같고, 1,000,000보다 작거나 같은 자연수이다. 자연수 xx가 주어졌을 때, ai+aj=xa_i + a_j = x (1i<jn)(1 \le i < j \le n)을 만족하는 (ai,aj)(a_i, a_j)쌍의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수열의 크기 n이 주어진다. 다음 줄에는 수열에 포함되는 수가 주어진다. 셋째 줄에는 x가 주어진다. (1 ≤ n ≤ 100000, 1 ≤ x ≤ 2000000)

출력

문제의 조건을 만족하는 쌍의 개수를 출력한다.

풀이

서로 다른 두 수의 합이 x가 되는 쌍의 개수를 세는 문제다. 정렬한 뒤 양끝에서 좁혀 오는 투 포인터를 쓰면 중복 없이 모든 후보를 효율적으로 확인할 수 있다.

현재 합이 x보다 작으면 더 큰 값을 만들기 위해 왼쪽 포인터를 올리고, 크면 오른쪽 포인터를 내린다. 정확히 x가 되면 정답 개수를 늘린 뒤 두 포인터를 모두 움직이면 된다.

정렬만 끝나면 합의 대소 비교로 포인터 이동 방향이 바로 정해진다. 완전탐색으로 두 수를 모두 고르지 않아도 된다는 점이 핵심이다.

코드

java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Main {
    private static final StringBuilder sb = new StringBuilder();
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        int n = Integer.parseInt(br.readLine());
 
        int[] arr = new int[n];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++)
            arr[i] = Integer.parseInt(st.nextToken());
 
        int x = Integer.parseInt(br.readLine());
 
        solve(n, arr, x);
        System.out.println(sb);
    }
 
    public static void solve(int n, int[] arr, int x) {
        Arrays.sort(arr);
 
        int count = 0;
        int left = 0;
        int right = n - 1;
 
        while (right > left) {
            int sum = arr[left] + arr[right];
 
            if (sum == x) {
                count++;
                left++;
                right--;
            } else if (sum > x) {
                right--;
            } else {
                left++;
            }
        }
 
        sb.append(count);
    }
}

복잡도

  • 시간 복잡도: 정렬 후 투 포인터로 한 번 훑으므로 O(NlogN)O(N \log N)이다.
  • 공간 복잡도: 입력 배열을 저장하므로 O(N)O(N)이다.

마무리

정렬 후 양끝 포인터를 좁혀 가면 합이 x인 쌍을 중복 없이 빠르게 셀 수 있다.