알고리즘

이진 탐색 _ Python

doobi 2023. 9. 27. 11:39

탐색 범위를 반으로 좁혀가며 빠르게 탐색하는 알고리즘

  • 정렬된 데이터에서 사용 가능
  • 시작점, 끝점, 중간점 3가지 변수 사용
  • 찾으려는 데이터와 중간점을 반복적으로 비교하여 원하는 데이터를 찾음

※ 시작점, 끝점, 중간점은 배열의 인덱스!!

배열의 크기가 n일 경우 처음 탐색을 시작할 때 시작점은 0, 끝점은 n-1이 된다. 

 

 

 

시간 복잡도

: O(logN)

한번 확인 할 때마다 원소 개수가 절반으로 줄어들기 때문에

 

 

코딩 테스트에서의 이진 탐색

간단해보이지만 실전에서 제대로 짜기 어려움

단골 문제니까 꼭 외우기 0.<

탐색 범위가 큰 상황에서 탐색을 가정하는 문제가 많다!

>> 탐색 범위가 2000,0000이 넘어가면 이진 탐색 고려

 

※ 데이터 단위가 천만이 넘어갈 경우 시간 복잡도 O(logN)정도가 되어야 한다.

 

구현 방법

1) 재귀 함수 사용

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)
    	else:
    		return binary_search(array,target,mid-1,end)

 

2) 반복문 사용

def binary_search(array, target, start, end):
	while start <= end:
    		mid = (start + end) // 2
        	if array[mid] == target:
        		return mid
        	elif array[mid] > target:
        		end = mid - 1
        	else:
        		start = mid + 1
    return None

 


 

~ 문제 풀이 ~

 

1. 부품 찾기(p.197)

메모리 제한: 128MB

시간 제한: 1초

탐색 범위: 최대 1,000,000 (N의 개수)

 

코드

import sys

# 이진 탐색 함수
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)
    else:
        return binary_search(array, target, mid + 1, end)


# 입력받기
N = int(input())
NList = sys.stdin.readline().rstrip().split()
M = int(input())
MList = sys.stdin.readline().rstrip().split()

NList.sort()
result = 0

for i in MList:

    if binary_search(NList, i, 0, N-1):
        print("yes", end=' ')
    else:
        print("no", end=' ')

 

시간 복잡도 

NList를 정렬할 때 : O(N * logN)

MList 값을 찾을 때: O(M*logN)

-> O((N+M) * logN)

 


2. 떡볶이 떡 만들기(p.201)

메모리제한: 128MB
시간 제한: 1초
탐색 범위: 10억

문제를 읽고 생각하기

문제:  떡을 한번에 잘라서 남는 길이의 합이 주어졌을 때, 떡을 얼마로 잘라야할까??

구해야 할 것: 떡을 자를 길이(H) (남은 길이의 합 계산 먼저가 아니라, 떡의 길이(H)에 따른 합으로 생각하기)

 

알고리즘 생각해보기

1. 여러 개의 떡이 있을 때, 0~가장 긴 떡의 길이 사이의 어떤 값(H)을 찾아야함.

- 시작점: 0, 끝점: 가장 긴 떡의 길이, 중간점: H

2. 이진 탐색으로 중간값으로 잘랐을 때 남은 떡의 합원하는 떡의 합을 비교

- 설정값으로 잘랐을 때 더 크면, 자르는 길이(H)를 늘리면 됨. 

- 반대로 더 작으면, 자르는 길이(H)를 줄이면 남는 양이 늘어남.

 

풀이 실수

1) 남는 길이 계산할 때 실수

#전체 합에서 mid*N만큼 빼주는거 ->  떡이 mid보다 짧을 때 안잘리니깐 안됨.
#total = sum(MList) - (N * mid)
total = 0
    for x in MList:
        if x > mid:
            total += x - mid

2) 가장 긴 떡 구할 때

# 내코드: 정렬해서 마지막 인덱스  --> max()함수 사용
# MList.sort()
# end = int(MList[-1])
end = max(MList)

 

코드

N, M = list(map(int, input().split(' ')))
MList = list(map(int, input().split()))

end = max(MList)
start = 0
result = 0
while(start <= end):
    mid = (start + end) // 2
    total = 0
    for x in MList:
        if x > mid:
            total += x - mid
    # 원하는 값 M 보다 남은 값(total)이 작을 경우, middle을 줄여서 total을 늘리기
    if M > total:
        end = mid - 1
    else:
        result = mid
        start = mid + 1

print(result)

 

'알고리즘' 카테고리의 다른 글

최단경로_Python  (0) 2023.10.04
DP(다이나믹 프로그래밍) _ Python  (0) 2023.09.28
구현_Python  (0) 2023.09.24
그리디 알고리즘_JAVA  (0) 2023.09.12
[프로그래머스] 성격 유형 검사하기 by Python  (0) 2022.09.02