Освоение двоичного поиска: поиск первого и последнего вхождения числа

Двоичный поиск – это мощный алгоритм, используемый для эффективного поиска определенного элемента в отсортированном массиве. В некоторых сценариях нам может потребоваться найти как первое, так и последнее вхождение определенного числа в массиве. В этой статье блога будут рассмотрены несколько методов выполнения этой задачи, а также приведены примеры кода.

Метод 1: два двоичных поиска.
Один простой подход — выполнить два отдельных двоичных поиска: один для поиска первого вхождения, другой для поиска последнего вхождения.

def find_first_occurrence(arr, target):
    left, right = 0, len(arr) - 1
    result = -1
    while left <= right:
        mid = left + (right - left) // 2
        if arr[mid] == target:
            result = mid
            right = mid - 1
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return result
def find_last_occurrence(arr, target):
    left, right = 0, len(arr) - 1
    result = -1
    while left <= right:
        mid = left + (right - left) // 2
        if arr[mid] == target:
            result = mid
            left = mid + 1
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return result
def find_first_and_last_occurrence(arr, target):
    first = find_first_occurrence(arr, target)
    last = find_last_occurrence(arr, target)
    return first, last

Метод 2: модифицированный двоичный поиск
Альтернативный подход включает изменение алгоритма двоичного поиска для совместного поиска первого и последнего вхождений.

def find_first_and_last_occurrence(arr, target):
    left, right = 0, len(arr) - 1
    first, last = -1, -1
    while left <= right:
        mid = left + (right - left) // 2
        if arr[mid] == target:
            first = mid
            right = mid - 1
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    left, right = 0, len(arr) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if arr[mid] == target:
            last = mid
            left = mid + 1
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return first, last

Метод 3: рекурсивный двоичный поиск
Мы также можем реализовать рекурсивную версию алгоритма двоичного поиска для поиска первого и последнего вхождений.

def find_first_and_last_occurrence(arr, target):
    first = find_first_occurrence(arr, target, 0, len(arr) - 1)
    last = find_last_occurrence(arr, target, 0, len(arr) - 1)
    return first, last
def find_first_occurrence(arr, target, left, right):
    if left > right:
        return -1
    mid = left + (right - left) // 2
    if arr[mid] == target and (mid == 0 or arr[mid - 1] != target):
        return mid
    elif arr[mid] < target:
        return find_first_occurrence(arr, target, mid + 1, right)
    else:
        return find_first_occurrence(arr, target, left, mid - 1)
def find_last_occurrence(arr, target, left, right):
    if left > right:
        return -1
    mid = left + (right - left) // 2
    if arr[mid] == target and (mid == len(arr) - 1 or arr[mid + 1] != target):
        return mid
    elif arr[mid] <= target:
        return find_last_occurrence(arr, target, mid + 1, right)
    else:
        return find_last_occurrence(arr, target, left, mid - 1)

В этой статье мы рассмотрели различные методы использования двоичного поиска для поиска первого и последнего вхождения числа в отсортированном массиве. Эти подходы обеспечивают эффективные решения этой проблемы, позволяя нам получить нужную информацию с временной сложностью O(log n), где n — размер массива. Освоив эти методы, вы сможете улучшить свое понимание алгоритмов двоичного поиска и применять их для решения различных задач программирования.