➕ 나동빈님 이코테에서 들은 내용을 기반으로 정리하고 공부한 게시글입니다.
정렬되어있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 방법이다. 탐색 범위가 절반씩 좁혀지기에 로그시간의 시간복잡도를 가진다. 이진 탐색을 수행하기 위해서는 시작점, 끝점, 중간점의 탐색 지점(인덱스)을 명시해주어 탐색 범위를 설정해야한다.
# 이진 탐색 소스코드 구현 (재귀 함수)
def binary_search(array, target, start, end):
if start > end:
return None
mid = (start + end) // 2 #소수점 아래는 버림
# 찾은 경우 중간점 인덱스 반환
if array[mid] == target:
return mid
# 중간점의 값보다 찾고자 하는 값이 작은 경우 왼쪽 확인
elif array[mid] > target:
return binary_search(array, target, start, mid - 1) #끝점 = 중간인덱스-1
# 중간점의 값보다 찾고자 하는 값이 큰 경우 오른쪽 확인
else:
return binary_search(array, target, mid + 1, end) #시작점 = 중간인덱스+1
# n(원소의 개수)과 target(찾고자 하는 값)을 입력 받기
n, target = list(map(int, input().split()))
# 전체 원소 입력 받기
array = list(map(int, input().split()))
# 이진 탐색 수행 결과 출력
result = binary_search(array, target, 0, n - 1) #(array, target, start, end)
if result == None:
print("원소가 존재하지 않습니다.")
else:
print(result + 1)
✨파이썬 이진 탐색 라이브러리 bisect
단계마다 탐색 범위는 1/2로 줄어들기에 연산 횟수는 logN에 비례한다. 따라서 시간 복잡도는 O(logN)이다.
절단기에 높이(H)를 지정하여 H보다 길이가 긴 떡은 H길이 만큼 잘리고, 길이가 짧은 떡은 잘리지 않습니다. 예를 들어 절단기 높이가 15cm일때 19,14,10,17cm인 떡은 4,0,0,2cm로 잘리게 되고 손님은 6cm만큼의 길이를 가져간다. 손님이 요청한 길이가 총 M일때, 적어도 M만큼의 떡을 얻기 위해 절단기에서 설정할 수 있는 높이의 최댓값을 구하여라.
이진탐색을 통해 끝점과 시작점을 움직여 M이 나올때까지 H를 조정한다.
1.
2.
3. M이 나올때까지 위과정을 반복한다.
# 떡의 개수(N)와 요청한 떡의 길이(M)을 입력
n, m = list(map(int, input().split(' ')))
# 각 떡의 개별 높이 정보를 입력
array = list(map(int, input().split()))
# 이진 탐색을 위한 시작점과 끝점 설정
start = 0
end = max(array) #가장 긴 떡의 길이
# 이진 탐색 수행 (반복적)
result = 0
while(start <= end):
total = 0
mid = (start + end) // 2
for x in array:
# 잘랐을 때의 떡볶이 양 계산
if x > mid:
total += x - mid
# 떡볶이 양이 부족한 경우 더 많이 자르기 (왼쪽 부분 탐색)
if total < m:
end = mid - 1
# 떡볶이 양이 충분한 경우 덜 자르기 (오른쪽 부분 탐색)
else:
result = mid # 최대한 덜 잘랐을 때가 정답이므로, 여기에서 result에 기록
start = mid + 1
print(result)
N개의 원소를 포함하고 있는 수열이 오름차순으로 정렬되어있다. 이때 수열에서 x가 등장하는 횟수를 구하여라.(단, 시간복잡도는 O(logN)이다.)
시간복잡도를 만족하기 위해서는 이진탐색을 이용해야한다. x가 등장하는 첫 위치, 마지막 위치를 찾아내 (x의 마지막 위치 - x의 첫 위치)+1 를 계산하면 x의 등장 횟수를 구할 수 있다.
또는 bisect을 사용해 x를 삽입할 수 있는 처음/마지막 위치를 찾아낸다.
from bisect import bisect_left, bisect_right
# x 개수 찾기
def count_by_range(array, left_value, right_value):
right_index = bisect_right(array, right_value) #6
left_index = bisect_left(array, left_value) #2
return right_index - left_index #4
n, x = map(int, input().split())
array = list(map(int, input().split()))
#값이 [x, x] 범위에 있는 데이터 갯수
count = count_by_range(array, x, x)
if count == 0:
print("해당 원소는 없습니다.)
else:
print(count)