❗️ 계속해서 업데이트 될 예정...
잘못된 부분이 있다면 알려주세요 🙏
정렬된 배열에서 타겟을 찾는 검색 알고리즘.
시간 복잡도는 O(log n)
이다.
흔히 리스트에 들어있는 값의 인덱스를 구할 때 index()
메소드를 사용한다. 하지만 이 메소드는 앞에서부터 하나씩 찾아가는 방식으로 시간 복잡도가 O(n)
이다. 찾는 값이 앞쪽에 있을 때는 index()
가 빠르겠지만 뒤쪽에 있으면 항상 일정한 시간 복잡도를 갖는 이진 검색 O(log n)
이 빠르다.
파이썬에서는 이진 검색을 구해주는 모듈 bisect
이 존재한다.
bisect
정렬된 리스트에 새로운 값을 삽입 후에 다시 정렬할 필요 없도록, 새로운 값을 어느 인덱스에 집어넣어야 정렬 상태를 유지하는지 알려준다.
bisect.bisect_left(a, x, lo=0, hi=len(a))
리스트a
에 새로운 값x
를 삽입할 위치를 찾는다. 기본적으로 전체 리스트a
에서 삽일 될 위치를 찾지만, 매개변수lo
와hi
를 넣어주면 리스트a
의 범위를 지정할 수 있다. 만약,a
에x
가 있으면 기존x
값 왼쪽에 삽입된다.bisect.bisect_right(a, x, lo=0, hi=len(a))
bisect.bisect(a, x, lo=0, hi=len(a))
기본적인 부분은bisect.bisect_left
과 같지만, 새로운 값을 삽입하는 위치가 오른쪽이다.
✏️ 내가 작성한 코드
import bisect
N = int(input())
A = list(map(int, input().split()))
M = int(input())
arr = list(map(int, input().split()))
A.sort()
for i in arr:
index = bisect.bisect_left(A, i)
if index < N and A[index] == i:
print(1)
else:
print(0)
시간 제한이 있기때문에
bisect
모듈을 사용하면 쉽게 풀린다.
💡 흥미로운 코드
import sys
input = sys.stdin.readline
N = int(input())
A = set(input().split())
M = int(input())
result = ''
for i in input().split():
result += '1\n' if i in A else '0\n'
print(result)
input().split()
을 하면 자동으로 리스트에 값이 들어간다. 단지, 요소가str
로 들어갈뿐이다.
이 문제에서는 요소가str
이든int
이든 상관 없기 때문에 굳이 list로 바꿔줄 필요 없다.
그렇기때문에for i in input().split()
처럼 따로input().split()
을 할당 안 해줘도 된다.
✏️ 내가 작성한 코드
N, M = map(int, input().split())
height = list(map(int, input().split()))
start, end, result = 0, max(height), 0
while start <= end:
mid = start + (end-start)//2 # 중간값
tree = sum([i-mid for i in height if i >= mid]) # 나무 길이 - 중간 값
if M > tree: # 나무 길이가 부족하면
end = mid - 1
else: # 나무 길이가 충분하면
result = max(result, mid)
start = mid + 1
print(result)
이진 검색을 할 때 흔히,
mid = (start+end)//2
로 오류를 범한다. 자료형에는 항상 최대값이 존재하는데,start+end
는 항상start
와end
보다 크게 되어 오버플로우가 발생할 수 있다.
그래서 항상mid = (start+end)//2
대신에,mid = start + (end-start)//2
를 사용해야한다.