시간 제한 1초
N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오.
첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -231 보다 크거나 같고 231보다 작다.
M개의 줄에 답을 출력한다. 존재하면 1을, 존재하지 않으면 0을 출력한다.
5
4 1 5 2 3
5
1 3 7 9 5
1
1
0
0
1
N의 최대값은 100,000 이므로 반복문을 이용하여 문제를 푼다면 시간 제한이 나올것 같다.
이러한 여러 데이터 중에서 원하는 값을 찾아낼 때는 이진 탐색을 사용하면 좋을것 같다.
이진 탐색 : 정렬된 데이터에서 원하는 데이터를 찾을 때 사용하는 알고리즘으로 시간 복잡도는 이다.
이진 탐색 과정은
- 현재 데이터에서 중앙값을 찾는다.
- 중앙값 > 찾는 데이터 일 때 중앙값을 기준으로 왼쪽에 있는 데이터셋을 선택한다.
- 중앙값 < 찾는 데이터 일 때 중앙값을 기준으로 오른쪽에 있는 데이터셋을 선택한다.
- 이렇게 중앙값을 기준으로 데이터를 찾다가 중앙값 == 찾는 데이터일 때 탐색을 종료한다.
예제 입력 1에 입력된 데이터를 기준으로 문제를 풀어보겠다.
N = 5, A[5] 배열에 저장될 데이터들은 4, 1, 5, 2, 3 순이다.
M = 5 이고 입력된 각 각의 1, 3, 7, 9, 5 데이터가 A에 포함되어 있다면 1을 출력 그렇지 않으면 0을 출력한다.
중앙값은 인덱스 시작점 부터 끝 인덱스 까지 더한 값에서 2를 나눠주면 된다. 그리고 찾는 값(여기서는 1)과 비교한다. 찾는 값이 중앙값 보다 작기 때문에 왼쪽에 있는 데이터 셋들로 범위를 변경한다.
중앙값은 (1 + 2)/2 로 1이기 때문에 찾는 값과 같은 수이기 때문에 1을 출력한다.
이런식으로 나머지 찾는 값들도 같은 이진탐색을 이용하면 된다.
이를 코드에 적용해보면 다음과 같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class 수찾기 {
static int[] A;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
A = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i = 0; i < N; i++) {
A[i] = Integer.parseInt(st.nextToken());
}
Arrays.sort(A); // 이진 탐색을 할때는 배열이 오름차순으로 정렬이 되어 있는 상태여야 한다.
StringBuilder sb = new StringBuilder();
int M = Integer.parseInt(br.readLine());
st = new StringTokenizer(br.readLine());
for(int i = 0; i < M; i++) {
int findNumber = Integer.parseInt(st.nextToken());
sb.append(binarySearch(findNumber)).append("\n");
}
System.out.println(sb);
}
private static int binarySearch(int num) {
int start = 0;
int end = A.length - 1;
while(start <= end) {
int mid = (start + end) / 2;
if(A[mid] < num) {
start = mid + 1;
}else if(A[mid] > num) {
end = mid - 1;
}else {
return 1;
}
}
return 0;
}
}
이진 탐색 자체는 이해하기 쉬웠지만 막상 구현하려고 보니 헷갈리는 부분도 있었다. 이진 탐색과 관련된 문제도 많이 풀면서 이해해보도록 하겠다.