이분탐색
말 그대로 두개로 나누어서 탐색하는 방식이다. 정확히는 정렬된 데이터에서 절반인 지점을 찍어 찾는 데이터가 맞는지 확인하는 과정을 계속해서 거쳐서 원하는 데이터를 찾는 방식이다.
Up Down 게임
Up Down
게임을 생각하면 이해가 좀 더 쉬울 것이다. 상대방이 1부터 100사이의 수 중에 하나를 선택하고 우리는 턴마다 숫자를 물어봐서 선택한 수와 (동일한지 / 큰지 / 작은지)를 알 수 있다.
여기서 1, 2, 3, 4, ... 이렇게 차례대로 부른다면 언젠가는 맞겠지만 우리는 이 턴을 최대한 줄이고 싶다. 운이 좋으면 한 번에 맞출 수도 있겠지만 여러번의 게임을 진행했을 때를 고려하자.
이 게임을 어떻게 플레이할지는 모두 알 것이다. 50
을 찍고 Up
이면 51
과 100
의 절반인 75
, 75
보다 작다면 51
과 74
의 절반인 62
, 이렇게 답의 범위를 줄여나갈 것이다.
// 생각한 숫자: K
void UpDownGame() {
int K = rand() % 100 + 1;
int s = 1, e = 100;
cout << "K: " << K << "\n";
while (s <= e) {
int mid = (s + e) / 2;
cout << "QUERY: " << mid << "\n";
if (K == mid) {
cout << "CORRECT!\n";
break;
}
else if (K > mid) {
cout << "UP\n";
s = mid + 1;
}
else {
cout << "DOWN\n";
e = mid - 1;
}
}
}
이런식으로 이분탐색을 구현하면 된다! 사고의 흐름과 일치하기에 금방 익숙해질 것이다.
데이터 찾기
그렇다면 다음과 같은 것도 할 수 있다. 아래와 같이 정렬된 수열이 있다. 인덱스는 1번부터 시작한다고 하자.1 4 12 49 50 55 59 72 100 101 103 107 129
해당 수열에서 100이 몇 번째 인덱스에 있는지 확인해보자. 이를 확인하기 위한 방법으로는 맨 처음 인덱스부터 100이 맞는지 차례대로 확인해나가는 방법이 있다. 위의 Up Down
게임과 마찬가지로 꽤나 오랜 시간이 걸릴 수 있다.
다른 방법으로는 방금 배운 이분탐색을 이용하는 것이다. 수열의 길이가 13이므로 1부터 13의 절반인 6번째 인덱스가 100
인지 비교하는 것이다.
55
이다. 더 작으므로 7부터 13의 절반인 10번째 인덱스가 100
인지 비교한다.
101
이다. 더 크므로 7부터 9의 절반인 8번째 인덱스가 100
인지 비교한다.
72
이다. 더 작으므로 9부터 9의 절반인 9번째 인덱스가 100
인지 비교한다.
100
이다!
이렇게 탐색을 해야하는 범위가 절반씩 줄어드는 것을 볼 수 있다. 따라서 최대 O(logN)번의 탐색으로 원하는 값을 찾을 수 있음이 보장된다.
조건
여기까지 글을 읽었더라면 어떤 형태의 데이터가 이분탐색을 사용할 수 있는 데이터인지를 알 수 있을 것이다. 바로 정렬되어 있는(sorted)
데이터이다. "Up Down
게임도 그런가요?" 라고 할 수 있는데, 잘 생각해보면 1, 2, 3, ..., 100 이 나열된 수열에서 데이터 찾기 를 진행하는 것과 같다.
데이터를 정렬된 형태로 주는 경우도 있으나 그렇지 않은 경우도 많기 때문에 대부분은 전처리에서 데이터를 정렬하는데 O(NlogN)이 들긴 한다...
매개변수 탐색
이분탐색과 거의 동일하다. 구현 내용도 99% 일치한다. 단지 문제의 유형이 다를 뿐이다. 이분탐색은 나열된 데이터에서 크기 비교를 하면서 특정 데이터를 찾는 것이라면 매개변수 탐색은 값이 변경되는 경계면을 찾는 것이다.
한 사람이 14:03
에 머리를 깎았다고 하자. 다른 한 사람은 이 사람이 머리를 당일 깎은 것만 안다. Up Down
게임처럼 시간을 물어볼 것이다. 여기서의 대답은 해당 시간에서 머리가 깎여 있었는가에 대해 Y/N
로 답을 해준다.
이러한 상황도 00:00
에서 23:59
의 절반인 11:59
를 물어본다.
N
, 아직 깎지 않았으니 그 다음인 12:00
에서 23:59
의 절반인 17:59
를 물어본다.
Y
, 깎은 상태이므로 이전에 깎았음을 알 수 있다. 새로운 구간에서 절반을 물어보는 것을 반복한다.
여기서 Y
의 대답을 받을 때마다 시간을 갱신해주면 된다.
'알고리즘' 카테고리의 다른 글
[정수론] 백준과 함께 하는 정수론 - 1 (0) | 2023.08.27 |
---|---|
최소 스패닝 트리(MST, Minimum Spanning Tree) (0) | 2023.08.27 |
최단 경로 알고리즘(1) (0) | 2023.08.27 |
알고리즘 문제 제작해보기(1) (0) | 2023.08.27 |
Inversion Counting (0) | 2023.08.13 |