backend/computer science

알고리즘 기초: 이진트리 (Binary Search)란? (+파이썬코드)

seul chan 2021. 4. 9. 16:23

Binary search

순차탐색: 특정 데이터를 찾기 위해서 앞에서부터 확인하는 방법
이진탐색: 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 방법

  • 시작점, 끝점, 중간점
  • ex. 이미 정렬된 10개의 데이터 중 값이 4인 원소를 찾는 예시
    • 시작접: 0, 끝점: 9, 중간점 4 (index)
    • 중간점을 기준으로 다시 끝점, 중간점을 옮김

시간복잡도: logN (단계마다 탐색범위를 2로 나누는 것)

이진탐색 소스: 재귀적 구현

def binary_search(array, target, start, end):
    if start > end:
        return None
    mid = (start + end) // 2
    # 찾은 경우 중간점 인덱스 반환
    if array[mid] == target:
        return mid
    # 중간점의 값보다 target이 작은 경우 왼쪽 확인
    # end를 mid - 1 index로
    elif array[mid] > target:
        return binary_search(array, target, start, mid - 1)
    # 중간점의 값보다 target이 큰 경우 오른쪽 확인
    # start를 mid+1 index로
    else:
        return binary_search(array, target, mid + 1, end)

이진탐색 소스: 반복문 구현

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

파이썬 이진탐색 라이브러리

  • bisect_left(a, x)
  • bisect_right(a, x)

값이 특정 범위에 속하는 데이터 개수 구하기

def count_by_range(a, leeft_value, right_value):
    right_index = bisect_right(a, right_value)
    left_index = bisect_left(a, left_value)
    return right_index - left_index

파라메트릭 서치

  • 최적화 문제를 결정 문제로 바꾸어 해결하는 기법
  • ex. 특정한 조건을 만족하는 가장 알맞은 값을 빠르게 찾는 문제
  • 이런 문제는 이진탐색으로 해결할 수 있다

문제

떡볶이 떡 만들기 문제

떡 길이가 일정하지 않는데 한봉지에 들어가는 총 길이는 절단기로 맞춰서 잘라줌

  • 절단기에 높이를 지정하면 줄지어진 떡을 한번에 절단
  • 높이(h)보다 긴 떡은 잘리고 낮은 떡은 안잘림
  • 손님이 요청한 길이가 M일 때 최소 M만큼의 떡을 얻기 위해 절단기에 설정할 수 있는 높이의 최댓값
  • 절단기의 높이는 0부터 10억

아이디어

  • 적절한 높이를 찾을때까지 이진탐색을 수행
  • 조건 만족을 확인한 후에 조건 만족여부에 따라 탐색 범위를 좁히기
  • 큰 탐색 범위(10억)를 보면 이진탐색을 떠올리면 됨
n, m = 4, 6
array = [19, 15, 10, 17]

# 시작, 끝점
start = 0
end = max(array)

result = 0
while(start <= end):
    total = 0
    mid = (start + end) // 2
    for x in array:
        # 잘린 떡 계산
        if m > mid:
            total += x - mid

    # 떡이 부족한 경우 왼쪽부분 탐색 (더 많이)
    if total < m:
        end = mid - 1
    # 충분한 경우 오른쪽 부분 탐색 (더 적게)
    else:
        result = mid  # 충분한 경우 (덜 잘렸을 때) result 기록
        start = mid + 1

정렬된 배열에서 특정 수 개수 구하기

오름차수 수열 N에서 x가 등장하는 개수 계산

  • 시간복잡도 O(logN)으로 설계하지 않으면 시간초과