반으로 나누어 가면서 목표하는 값을 찾아나가는 방법이다. 절반씩 나누기 때문에 시간복잡도가 O(logn)이다. 하지만 이 방법은 배열이 오름차순으로 정렬됐을 때만 사용가능하다. 만약 오름차순으로 정렬됐고, 탐색을 해야한다면 이분 탐색이 유용하다.
오름 차순으로 정렬된 배열에서 목표 값과 일치하는 값을 찾음
arr = [1,2,5,7,9]
target = 7
left, right = 0, len(arr)-1
answer = -1 # 못 찾았을 경우 -1
while(left <= right) {
mid = (left + right) // 2
if arr[mid] == target:
answer = mid
break # mid 위치가 답
elif arr[mid] > taget: right = mid - 1
else: left = mid + 1
}
print(answer)
이분 탐색을 이용한 방법으로 키 값보다 큰 값이 최초로 나오는 지점의 인덱스를 찾고자 할 때 사용한다.
전체적인 과정은 이분 탐색과 유사하다.
arr = [1,2,5,7,9]
# 반복문
target = 7
left, right = 0, len(arr)-1
answer = -1
while(left <= right) {
mid = (left + right) // 2
if arr[mid] <= target: left = mid+1
else:
answer = mid
right = mid - 1 # mid가 답이 될 수도 있으므로
}
answer = left
# 재귀
def upper_bound(s, e, p):
if s >= e:
return s
mid = (s + e) // 2
if p < arr[mid]:
return upper_bound(s, mid, p)
else:
return upper_bound(mid + 1, e, p)
이분 탐색을 이용한 방법으로 키 값보다 크거나 같은 값이 나오는 최초의 인덱스를 찾고자 할 때 사용한다.
arr = [1,2,5,7,9]
target = 7
left, right = 0, len(arr)-1
while(left < right) {
mid = (left + right) // 2
if arr[mid] >= target: right = mid # mid가 닶이 될 수도 있으므로
else: left = mid + 1
}
answer = left
arr = [1,2,5,7,9]
target = 7
left, right = 0, len(arr)-1
answer = -1
while(left <= right) {
mid = (left + right) // 2
if arr[mid] >= target:
answer = mid
right = mid - 1 # mid가 닶이 될 수도 있으므로
else: left = mid + 1
}
answer = left
# 재귀
def lower_bound(s, e, p):
if s >= e: # 재귀는 s, e가 같은지 먼저 확인하므로 무한 mid로 해도 무한루프에 빠지지 않는다.
return s
mid = (s + e) // 2
if p <= arr[mid]:
return lower_bound(s, mid, p)
else:
return lower_bound(mid+1, e, p)
=> lower_bound와 upper_bound가 같을 경우, 키 값과 같은 값이 없다는 것이다. Lower_bound는 키 값보다 크거나 같은 지점의 최초 위치를 찾는 것인데 같은 값이 없으면 큰 값을 가리키기 때문이다.