이분 탐색
**이분 탐색(Binary Search)**는 정렬된 데이터에서 특정 값을 효율적으로 찾기 위해 사용하는 알고리즘이다.
데이터를 절반씩 나누어 탐색 범위를 좁혀가며, 시간 복잡도가 O(\log N\)인 효율적인 방법이다.
값의 범위가 0~10 까지이고, 만약 찾고자 하는 값이 3 이라 하면 아래와 같은 방식으로 이뤄진다.
1. 중간값을 구한다.
2. 중간값보다 찾는 값이 작으면, 범위를 시작값 ~ 중간값 -1 으로 재조정한다.
3. 중간값보다 찾는 값이 크면, 범위를 중간값+ 1 ~ 마지막값 으로 재조정한다.
4. 중간값이 찾는 값과 같을 때까지 1~3을 반복한다.
재귀와 반복문 둘 중 하나로 구현 가능하다.
def binary_search(arr, target):
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1 # 값을 찾지 못함
arr = [2, 4, 7, 10, 15, 20]
print(binary_search(arr, 10)) # 출력: 3
def bs_search(start, end, target) :
mid = (start + end) // 2
if(start <= end):
if(arr[mid] == target): return mid
elif(arr[mid] < target):
return bs_search(mid + 1, end, target)
else:
return bs_search(start, mid - 1, target)
else:
return False
print(bs_search(0, 5, 10)) # 출력: 3
파라메트릭 써치
파라메트릭 서치는 "특정 조건을 만족하는 값이 존재하는가?"를 판단하는 문제를 기반으로, 그 값의 범위를 이진 탐색하여 최적의 값을 효율적으로 찾는 방법이다. 즉 최적화 문제 -> 결정문제 로 만들고, 값을 찾기 위해 이분탐색을 활용하는것.
특정 조건을 만족하는 최적화된 N 값을 도출한다. [최적화 문제]
범위 N이 특정 조건을 만족하는가? [결정 문제]
최적화 문제: 어떤 조건을 만족하는 최대, 최소값을 구하는 문제
결정 문제: 답이 Y/N으로 갈리는 문제
전체 값이 될 수 있는 후보들 A~Z 중
A,B,C,E,D 가 조건에 맞니? -> YES
A,B,C 가 조건에 맞니? -> NO
E,D 가 조건에 맞니? -> YES
E 가 조건에 맞니? -> YES
D 가 조건에 맞니? -> NO
이런 식으로 이진탐색을 이용해 범위를 좁혀가면서 답을 찾아가는 방식이다.
문제 01 부품 찾기
문제 내용
동빈이네 전자 매장에는 부품이 N개 있다. 각 부품은 정수 형태의 고유한 번호가 있다. 어느 날 손님이 서개 종류의 부품을 대량으로 구매하겠다며 당일 날 견적서를 요청했다. 동빈이는 때를 놓치지 않고 손님이 문의한 부품 서개 종류를 모두 확인해서 견적서를 작성해야 한다. 이때 가게 안에 부품이 모두 있는지 확인하는 프로그램을 작성해보자.
예를 들어 가게의 부품이 총 5개일 때 부품 번호가 다음과 같다고 하자.
N = 5
[8, 3, 7, 9, 2]
손님은 총 3개의 부품이 있는지 확인 요청했는데 부품 번호는 다음과 같다.
M = 3
[5, 7, 9]
이때 손님이 요청한 부품 번호의 순서대로 부품을 확인해 부품이 있으면 yes룰, 없으면 no 를 출력한다. 구분은 공백으로 한다.
문제 풀이
일단 이진탐색을 하려면 값이 정렬되어 있으므로 정렬 부터 한 다음, 이진 탐색을 통해 값을 찾아낸다.
N, M = map(int,input().split())
goods = sorted(list(map(int,input().split())))
orders = sorted(list(map(int,input().split())))
def bs_search(start, end, target) :
mid = (start + end) // 2
if(start <= end):
if(goods[mid] == target): return True
elif(goods[mid] < target):
return bs_search(mid + 1, end, target)
else:
return bs_search(start, mid - 1, target)
else:
return False
for item in range(0,M):
print(orders[item], ' :: ' , bs_search(0, N, orders[item]))
# 5 3
# 8 3 7 9 2
# 5 7 9
문제 02 떡볶이 떡 만들기
문제 내용
오늘 동빈이는 여행 가신 부모님을 대신해서 떡집 일을 하기로 했다. 오늘은 떡볶이 떡을 만드는 날이다. 동빈이네 떡볶이 떡은 재밌게도 떡볶이 떡의 길이가 일정하지 않다. 대신에 한 봉지 안에 들어가는 떡의 총 길이는 절단기로 잘라서 맞춰준다.
절단기에 높이 ( H ) 를 지정하면 줄지어진 떡을 한 번에 절단한다. 높이가 H 보다 긴 떡은 H 위의 부분이 잘릴 것이고, 낮은 떡은 잘리지 않는다. 예를 들어 높이가 19, 14, 10, 17cm인 떡이 나란히 있고 절단기 높이를 15cm로 지정하면 자른 뒤 떡의 높이는 15, 14’ 10, 15cm가 될 것이다. 잘린 떡의 길이는 차례대로 4, 0, 0,2cm이다. 손님은 6cm만큼의 길이를 가져간다.
손님이 요청한 길이가 M일 때 적어도 M을 가져갈 수 있는 절단기의 최대 높이를 구하시오.
문제 풀이
특정 범위가 해당 조건을 만족하는가? 를 주안점으로 문제를 풀도록 한다.
이 때 범위를 잡는 방식을 이분탐색을 이용한다. (파라메트릭 써치)
그리고 문제 내용을 보면 적어도 M을 가져가야 하는 것이기 때문에, 손님이 가져갈 분량이 M을 넘을 때에도 답을 갱신해 두어야 한다.
4 1
1 1 1 1
--> 답 0
다만 이코테 책에 반례들이 없어서.. 이게 모든경우를 다 통과할지는 모르겠다;
# 4 6
# 19 15 10 21
# 나머지가 6이 될 수 있는 절단기 높이 H의 최댓값.
N, M = list(map(int,input().split()))
cakes = list(map(int,input().split()))
mx = max(cakes)
cut = 0
ans = 0
def isTarget(mid):
global N
total = 0 # 손님이 가져갈 분량
for c in range(0, N):
cake = cakes[c]
total += (cake - mid) if cake > mid else 0
ret = 1
if(total > M): ret = 2
elif(total < M): ret = 3
return ret
while True:
mid = (cut + mx) // 2
succed = isTarget(mid)
if(succed == 1):
ans = mid # 혹시나 딱 맞게 되면 갱신후 바로 종료
break
elif(succed == 2):
ans = mid # 최대한 덜 잘랐을 때가 정답이라 일단 갱신
cut = mid + 1
else:
mx = mid - 1
if(cut > mx):
break
print('ans', ans)'알고리즘' 카테고리의 다른 글
| [이코테] 바닥공사 (1) | 2024.12.09 |
|---|---|
| [이코테] 1로 만들기, 개미전사 (1) | 2024.12.09 |
| [이코테] 음료수 얼려 먹기, 미로탈출 (1) | 2024.12.07 |
| [항해 99 코테 스터디] 숫자짝궁 (2) | 2024.12.01 |
| [항해 99 챌린지 / 이코테] 그리디, 예시문제 (큰 수의 법칙, 숫자카드게임, 1이 될때까지) (1) | 2024.11.30 |