용어 정의

정렬된 배열에서 특정 값을 찾을 때 반절씩 쪼개가면서 찾는 것

구현

int BinarySearch(vector<int> &a, int target) {
	int left = 0;
	int right = a.size() - 1;
	while(right >= left) {
		int mid = left + (right - left) / 2;
		if(a[mid] == target) return mid;
		else if (a[mid] < target) left = mid + 1;
		else right = mid - 1;
	}
	return -1;
}

응용 : 일반화 이진탐색

특정 조건이 만족되기 시작하는 최초의 값을 찾기

예시 : C++의 std::lower_bound. 정렬된 배열 a에서 a[i] >= key를 만족하는 최소 인덱스 i를 반환한다. i보다 크거나 같은 모든 인덱스 x에서 a[x] key를 만족한다.

구현

bool check(int x) {// 조건 검증 함수... }
int GeneralBS(vector<int> &a, int key){
	int left = 0;
	int right = a.size() - 1;
	while(right >= left) {
		int mid = left + (right - left) / 2;
		if(check(a[mid])) mid = right;
		else mid = left;
	}
	return right;
}

예시

나이 맞추기

초면인 사람이 자기 나이가 a살 이상 b살 미만이라 했다. 내가 물어보면 예/아니오로 답해준다. 나이를 맞추시오.

int GetAge(int a, int b) {
	int left = a;
	int right = b;
	while(right >= left) {
		int mid = left + (right - left) / 2;
		if(나이가 mid 이하) mid = right;
		else mid = left;
	}
	return right;
}

사격왕

N개의 풍선이 초기 상태에 각각 Hi 에 있고, 1초마다 Si 씩 상승한다. 모든 풍선을 쏴서 터뜨리려고 하는데, 터뜨릴 때 풍선의 높이만큼 페널티가 발생한다. 최종 페널티는 발생한 페널티 중 최대 값이다. 가장 작은 페널티를 구하라.

// N개의 풍선이 있을 때, 모든 풍선을 터뜨리는 데 걸리는 시간은 N초임
// 초기 상태에서 N초 후에 가장 높게 있는 풍선의 높이가 최대 페널티임.
 
int FindShooter(int N, vector<int> &H, vector<int> &S){
	int M = 0;
	for(int i = 0; i<N; i++) M = max(M, H[i] + S[i] * N);
 
	int left = 0, right = M;
	while(right >= left) {
		int mid = left + (right - left) / 2;
		bool needSkip = false;
		vector<long long> t(N, 0); // 각 풍선을 쏴야 하는 제한시간
		for(int i = 0; i < N; i++) {
			if(H[i] < mid) {
				left = mid;
				needSkip = true;
				break;
			}
			else {
				t[i] = (mid - H[i]) / S[i];
			}
		}
		sort(t.begin(), t.end());
		for(int i = 0; i < N; i++) {
			if(t[i] < i) needSkip = true;
		}
		if(!needSkip) right = mid;
		else left = mid;
	}
	return right;
}
 

참고자료

문제 해결력을 높이는 알고리즘과 자료 구조