Изучите бинарный поиск в Python: пошаговое объяснение, примеры кода, разбор типичных ошибок и реальные задачи с собеседований. Начните искать быстрее прямо сейчас!
Представьте: на собеседовании вам дают отсортированный массив из миллиона чисел и просят найти индекс цели. Ваш первый инстинкт — пройтись по всем элементам? Линейный поиск сделает до миллиона сравнений, а бинарный — всего около 20. Разница между «завалить собеседование» и «получить оффер». В этой статье вы не просто выучите алгоритм, а поймёте, как эксплуатировать порядок для сокращения пространства поиска вдвое на каждом шаге.
Бинарный поиск — это алгоритм для поиска элемента в отсортированном массиве. Его сила в том, что каждое сравнение отбрасывает половину оставшихся элементов. Представьте игру: я загадал число от 1 до 100, а вы угадываете. Вы не будете перебирать по порядку — вы назовёте 50, я скажу «больше» или «меньше», и вы отбросите половину чисел. Так и здесь: после k шагов остаётся N / 2^k кандидатов. Чтобы диапазон сузился до одного элемента, нужно k = log₂ N шагов. Отсюда сложность O(log n).
Магия не в арифметике, а в инварианте: если цель существует, она всегда находится внутри текущего окна [low, high]. Мы никогда не выбрасываем сегмент, который может содержать ответ, потому что сравнение (mid < target или mid > target) точно указывает, какая половина неактуальна.
Вот классическая реализация бинарного поиска:
def binary_search(arr, target):
"""Бинарный поиск в отсортированном массиве.
Возвращает индекс target или -1, если элемент не найден."""
low = 0
high = len(arr) - 1
while low <= high:
mid = (low + high) // 2 # целочисленное деление
guess = arr[mid]
if guess == target:
return mid # нашли!
elif guess < target:
low = mid + 1 # цель справа
else:
high = mid - 1 # цель слева
return -1 # цели нетПояснение:
- Условие low <= high гарантирует, что мы не вышли за границы окна.
- mid делит окно пополам; сравнение говорит, какую половину отбросить.
- Обновляя low или high, мы сохраняем инвариант.
Пример использования:
nums = [1, 3, 5, 7, 9, 11, 13]
print(binary_search(nums, 7)) # 3
print(binary_search(nums, 2)) # -1+1 или -1 при сдвиге границ — ведёт к бесконечному циклу или пропуску цели. Всегда обновляйте low = mid + 1 и high = mid - 1.low + high может переполниться. Безопасная формула: mid = low + (high - low) // 2. В Python проблем нет, но привычка полезная.low < high вместо low <= high — может пропустить элемент, когда low == high.Дан массив, который был отсортирован, а затем повёрнут в неизвестной точке. Найдите цель за O(log n).
Идея: Даже если массив не глобален, одна половина относительно середины всегда отсортирована. Определите, какая половина отсортирована, и решите, где искать.
def search_rotated(nums, target):
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[mid] == target:
return mid
# левая половина отсортирована
if nums[low] <= nums[mid]:
if nums[low] <= target < nums[mid]:
high = mid - 1
else:
low = mid + 1
# правая половина отсортирована
else:
if nums[mid] < target <= nums[high]:
low = mid + 1
else:
high = mid - 1
return -1Дан API isBadVersion(version), который возвращает True для плохих версий (все версии после первой плохой — тоже плохие). Найдите первую плохую версию.
Идея: Предикат монотонный (False...False, True...True). Бинарный поиск по предикату найдёт точку перехода.
def first_bad_version(n):
low, high = 1, n
while low < high:
mid = (low + high) // 2
if isBadVersion(mid):
high = mid # первая плохая версия <= mid
else:
low = mid + 1 # первая плохая версия > mid
return lowОсвоив бинарный поиск, вы перестанете автоматически использовать линейный перебор. Вместо этого вы начнёте задавать вопросы:
Если ответ «да», вы превращаете линейный перебор в логарифмический спринт. На практике это означает обработку миллионов записей за миллисекунды, быстрые API-поиски и восхищение интервьюеров.
Это также открывает путь к продвинутым техникам: экспоненциальный поиск, параллельный бинарный поиск и даже бинарный поиск по ответу (шаблон «поиск в пространстве решений» для задач вроде «минимальная скорость поедания бананов» или «грузоподъёмность для доставки»).
Закрепите навык: дана отсортированная двумерная матрица, где каждая строка и каждый столбец отсортированы по возрастанию. Напишите алгоритм поиска цели за O(m + n). Затем улучшите до O(log(m·n)), представив матрицу как плоский отсортированный массив и применив бинарный поиск.
Попробуйте, напишите код и поделитесь решением в комментариях. Увидим, как вы используете «кольцо всевластия» бинарного поиска в своих приключениях.
Держите массивы отсортированными, а мысли — ясными. И помните: иногда самые большие победы приходят от деления проблемы пополам, а не от пробивания её насквозь. Счастливого кода! 🚀
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →