Coding Test/Baekjoon

[백준 골드 4] 1253번: 좋다

개발소 2023. 12. 7. 22:36

문제

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

 

1253번: 좋다

첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수)

www.acmicpc.net

 

 

풀이

  • N개의 수가 주어질 때, 어떤 수가 다른 두 수의 합으로 나타낼 수 있다면 "좋다"라고 한다.
  • 주어진 N개의 수 중 좋은 수의 개수를 출력해야 한다.
  • 같은 값의 수가 주어질 수도 있지만 서로 다른 수로 취급한다.
  • N은 1에서 2000 사이이고, 주어지는 수는 |Ai| ≤ 1,000,000,000 의 정수이다.

 

투포인터를 사용해 N개의 수를 탐색하는 방법으로 풀었다. 이때, 수의 범위가 크므로 Long형 배열로 입력받고 정렬하였다.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());

long numbers[] = new long[N];

StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
    numbers[i] = Long.parseLong(st.nextToken());
}

Arrays.sort(numbers);

 

numbers 배열의 모든 수를 좋은 수인지 판별하기 위해 for문을 사용해 배열 전체를 탐색하였다. 첫번째 인덱스와 마지막 인덱스를 포인터로 사용하고, 포인터가 가리키는 값의 합과 타깃으로 한 수가 같은지 판별하는 while문을 만들었다. while문의 조건은 포인터가 만나게 되는 경우로 정의하였다.

for (int i = 0; i < N; i++) {
    long target = numbers[i];
    int start = 0;
    int end = N - 1;
    long sum = 0;

    while (start < end) {
    	sum = numbers[start] + numbers[end];
        ...
    }
}

 

포인터를 사용해 비교하는 것은 크게 세가지 경우이다. 포인터가 가리키는 값의 합과 타깃을 비교하였을 때, 큰 경우, 작은 경우, 그리고 일치하는 경우이다.

오름차순으로 정렬하였기 때문이 비교한 결과 합보다 타깃이 더 크다면 앞의 인덱스가 +1 만큼 움직여 합의 크기를 키워줘야 한다. 반대로 합보다 타깃이 더 작다면 뒤의 인덱스를 -1 만큼 움직여 합의 크기를 작게 만들어 줘야한다.

if (sum < target) {
    start++;
} else if (sum > target) {
    end--;
}

 

처음에는 다른 투포인터 문제처럼 else에 결과값을 늘리고 break를 하였지만, 생각해보니 포인터가 가리키는 값이 타깃으로 한 숫자인 경우도 제외해야 했다. start나 end 포인터가 타깃에 해당하는 i 인덱스를 가리킨다면, 그래도 통과하면 된다.

else {
    if (start != i && end != i) {
        cnt++;
        break;
    } else if (start == i) {
        start++;
    } else if (end == i) {
        end--;
    }
}

 

 

전체 코드 (Java)

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

public class Main {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());

		long numbers[] = new long[N];

		StringTokenizer st = new StringTokenizer(br.readLine());
		for (int i = 0; i < N; i++) {
			numbers[i] = Long.parseLong(st.nextToken());
		}

		Arrays.sort(numbers);

		int cnt = 0;

		for (int i = 0; i < N; i++) {
			long target = numbers[i];
			int start = 0;
			int end = N - 1;
			long sum = 0;

			while (start < end) {
				sum = numbers[start] + numbers[end];

				if (sum < target) {
					start++;
				} else if (sum > target) {
					end--;
				} else {
					if (start != i && end != i) {
						cnt++;
						break;
					} else if (start == i) {
						start++;
					} else if (end == i) {
						end--;
					}
				}
			}
		}

		System.out.println(cnt);

	}

}

 

 

후기

투포인터는 늘 복잡하게 생각하지 말고 주어진 조건을 차근차근 구현하면 되는 것 같다. 어느정도 감을 잡은듯 하다.