이분 탐색 (Binary Search)
정의
이분 탐색 (Binary Search) 은 정렬된 시퀀스에서 목표값의 위치를 O(log N) 에 찾는 알고리즘. 매 단계에서 후보 구간을 절반으로 줄인다.
탐색이 본질이 아니어도, “답에 대해 단조성이 성립” 하기만 하면 답 자체를 이분 탐색 할 수 있다 (parametric search). 이 형태가 정렬 다음으로 PS 에서 가장 자주 등장한다.
문제 상황과 동기
길이 N 의 정렬된 배열에서 값 x 의 존재/위치를 알고 싶다.
- naive: 앞에서부터 선형 스캔. O(N).
- 이분 탐색: 매 단계에서 중간값과 비교, 후보 절반 버림. O(log N).
N = 10^9 일 때, naive 는 10초+ 걸리지만 이분 탐색은 약 30 단계로 끝난다. 단조성 (monotonicity) 만 있으면 검색·최적화 양쪽에 모두 적용 가능.
핵심 통찰: “x 가 후보 구간 어디에 있을 수 없다” 가 한 비교로 절반 결정.
시각화
핵심 아이디어
invariant: 답은 항상 [lo, hi] 구간 안에 있다. 매 단계에서 mid = (lo + hi) / 2 를 보고 비교.
초기: lo = 0, hi = N - 1
while lo <= hi:
mid = (lo + hi) / 2
if arr[mid] == x: 발견
elif arr[mid] < x: lo = mid + 1 // 오른쪽 반쪽
else: hi = mid - 1 // 왼쪽 반쪽
없으면 -1 또는 삽입 위치
각 단계마다 구간 길이가 절반. 최대 ⌈log₂ N⌉ 단계.
알고리즘
표준 (값 찾기)
binary_search(arr, x):
lo = 0, hi = N - 1
while lo <= hi:
mid = lo + (hi - lo) / 2 # 오버플로우 방지
if arr[mid] == x: return mid
elif arr[mid] < x: lo = mid + 1
else: hi = mid - 1
return -1
lower_bound (x 이상의 첫 위치)
lower_bound(arr, x):
lo = 0, hi = N
while lo < hi:
mid = lo + (hi - lo) / 2
if arr[mid] < x: lo = mid + 1
else: hi = mid
return lo
hi = N 이 가능 (모든 원소가 x 보다 작은 경우). 표준 STL std::lower_bound 와 동작 동일.
parametric search (답에 이분 탐색)
f(k) = (k 가 답으로 가능한가) 가 단조 (false…false true…true) 이면, 가장 작은 k 를 이분 탐색.
parametric_search(lo, hi):
while lo < hi:
mid = lo + (hi - lo) / 2
if f(mid): hi = mid # mid 가 가능 -> 답 후보
else: lo = mid + 1
return lo # 가장 작은 가능 답
구현
// O(log N) 이분 탐색, lower_bound 변형
#include <bits/stdc++.h>
using namespace std;
int main() {
int n; cin >> n;
vector<int> a(n);
for (auto& v : a) cin >> v;
sort(a.begin(), a.end());
int q; cin >> q;
while (q--) {
int x; cin >> x;
int lo = 0, hi = n;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < x) lo = mid + 1;
else hi = mid;
}
if (lo < n && a[lo] == x) cout << lo << "\n";
else cout << -1 << "\n";
}
}5
1 3 5 7 9
3
5
1
92
0
4복잡도
| 항목 | 값 |
|---|---|
| 시간 | O(log N) per query |
| 공간 | O(1) iterative, O(log N) recursive (stack) |
| 전제 | 정렬되어 있어야 함 (정렬 자체는 O(N log N)) |
| 비교 횟수 | 약 ⌈log₂(N+1)⌉ |
변형 / 활용
| 형태 | 예시 |
|---|---|
| 값 찾기 | arr 에 x 가 있는가 / 어디에 있는가 |
| lower_bound / upper_bound | x 이상 / x 초과의 첫 위치 |
| Parametric search | ”답을 이분 탐색”: [[Parametric Search |
| 회전된 배열 | 어디서 회전했는지 판별 후 절반에서 탐색 |
| 2차원 행/열 단조 | 한 행에서 이분 + 다음 행 / staircase |
| **[[Ternary Search | 삼분 탐색]]** |
함정
1. 정렬 가정
이분 탐색은 정렬된 입력 가정. 정렬되지 않은 입력에 적용하면 답이 틀린다 (혹은 0 회 매칭).
2. mid 계산 오버플로우
(lo + hi) / 2 는 lo, hi 가 큰 정수일 때 오버플로우 가능. lo + (hi - lo) / 2 가 안전 표준.
3. <= vs < 의 경계 처리
while (lo <= hi) // 폐구간 [lo, hi], 종료 시 lo == hi + 1
while (lo < hi) // 반열린 구간 [lo, hi), 종료 시 lo == hi
둘 다 맞지만 섞으면 무한 루프 / off-by-one. 한 가지 스타일을 일관되게.
4. 실수 이분 탐색
부동소수점 이분 탐색은 고정 횟수 (예: 100 회) 로 종료하는 것이 안전. lo < hi - 1e-9 같은 조건은 정밀도 문제.
for (int i = 0; i < 100; i++) {
double mid = (lo + hi) / 2;
if (f(mid)) hi = mid;
else lo = mid;
}
표준 라이브러리
| 언어 | 함수 |
|---|---|
| C++ | std::lower_bound, std::upper_bound, std::binary_search |
| Python | bisect.bisect_left, bisect.bisect_right |
| Java | Arrays.binarySearch, Collections.binarySearch (객체) |
| Rust | slice::binary_search, partition_point |
| JavaScript | (표준 없음, 직접 구현) |
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 1920 | 수 찾기 | - | kokoa-lab |
| BOJ 10816 | 숫자 카드 2 | - | kokoa-lab |
| BOJ 2295 | 세 수의 합 | - | kokoa-lab |
| BOJ 1654 | 랜선 자르기 | - | kokoa-lab |
| BOJ 2110 | 공유기 설치 | - | kokoa-lab |
| BOJ 1300 | K번째 수 | - | kokoa-lab |
참고
- 매개 변수 탐색
- 삼분 탐색
- 정렬 알고리즘
- Aliens Trick (lambda 에 대한 이분 탐색)
이 글의 용어 (4개)
- 병렬 이분 탐색 (Parallel Binary Search)algorithm
- 정의 병렬 이분 탐색 (Parallel Binary Search, PBS) 은 Q 개의 쿼리를 각각 독립적으로 이분탐색하지 않고, 모든 쿼리의 이분탐색을 라운드별로 동시에 진행하…
- 삼분 탐색 (Ternary Search)algorithm
- 정의 삼분 탐색 (Ternary Search) 은 단봉 (unimodal) 함수의 극값 (최대 / 최소) 을 O(log N) 에 찾는 알고리즘. 구간을 3등분하는 두 점 , 에서…
- 정렬 알고리즘algorithm
- 정의 정렬 (sort) 은 원소들의 컬렉션을 어떤 전순서 (total order) 기준으로 재배열하는 것. 알고리즘 입문의 정석 주제이자, 데이터베이스·검색·통계 등 모든 시스템…
- Aliens Trickalgorithm
- 정의 Aliens Trick (또는 WQS Binary Search, Lagrange Optimization) 은 "정확히 K 개 선택" 같은 까다로운 제약을 가진 DP 를, 제…
이 개념을 다룬 위키 페이지 (11)
- wiki머지 소트 트리 (Merge Sort Tree)
- wiki분할 정복 (Divide and Conquer)
- wiki최장 증가 부분 수열 (Longest Increasing Subsequence)
- wiki두 포인터 (Two Pointer)
- wikiGolden-section Search: 단봉 함수 최적화
- wiki수치해석 (Numerical Analysis)
- wiki값 / 좌표 압축 (Coordinate Compression)
- wiki병렬 이분 탐색 (Parallel Binary Search)
- wikiMITM (Meet in the Middle)
- wiki매개 변수 탐색 (Parametric Search)
- wiki삼분 탐색 (Ternary Search)
💬 댓글