Бесплатная бета: 60 дней полного доступа, без карты.мест осталось: 84Зарегистрироваться бесплатно

Мы используем необходимые куки для работы сайта (вход и язык). Если ты согласишься, мы также загрузим Google Analytics, чтобы видеть, какие страницы читают, и Google reCAPTCHA для защиты форм обратной связи и сообщений об ошибке от спама. Политика конфиденциальности

← Блог
Как готовиться

Бинарный поиск по ответу: приём для задач про минимальную скорость и вместимость

· 2026-10-08

Короткий ответ. Бинарный поиск по ответу перебирает не массив, а диапазон возможных ответов. Берём кандидата, проверяем за O(n), подходит ли он, и отбрасываем половину диапазона. Приём нужен в задачах «минимальная скорость», «наименьшая вместимость», «максимальное минимальное расстояние». Ниже устройство, функция проверки, код на Python и задача про Коко и бананы.

Что такое бинарный поиск по ответу?

Обычный бинарный поиск ищет число в отсортированном массиве. Здесь массив не отсортирован. Зато сами ответы образуют диапазон от lo до hi.

Про каждого кандидата можно спросить: хватает ли его? Ответы на этот вопрос монотонны. До какого-то порога все «нет», после него все «да». Бинарный поиск находит порог.

Для метода нужны три вещи: нижняя граница, верхняя граница и функция проверки. Границы задают диапазон, проверка отвечает на вопрос про середину.

Наименьшая вместимость корабля, которая успевает в срок
smallestFeasible(4, 16, (cap) => canShip([3, 2, 2, 4, 1, 4], 3, cap))
кандидаты на вместимость
4
5
6
7
8
9
10
11
12
13
14
15
16

lo

hi
canDo(cap): груз на каждый день
пусто
lo = 4hi = 16days = 3

Нужно отправить грузы [3, 2, 2, 4, 1, 4] по порядку за 3 дня. Вместимость не меньше 4 (самый тяжёлый груз) и не больше 16 (всё сразу).

Гонка скорости
Два способа найти самый маленький корабль, который перевезёт 24 посылок за 3 дня

Столбики: веса посылок. Каждая проверка вместимости читает их все по порядку.

Одна операция: одно чтение веса посылки. За каждый кадр все дорожки делают одинаковое число операций, поэтому медленная отстаёт.

Перебор всех вместимостей O(n·S)
операций: 0
Бинарный поиск по ответу O(n log S)
операций: 0

 

А если чисел больше

Операции для n чисел и примерное время при 100 миллионах простых операций в секунду. Это оценка по тому же счёту, а не замер.

n = 1 000
Перебор всех вместимостей2,2 млн · 22 мс
Бинарный поиск по ответу12,7 тыс. · меньше 1 мс
n = 100 000
Перебор всех вместимостей21,7 млрд · 3,6 мин
Бинарный поиск по ответу1,9 млн · 19 мс
n = 10 000 000
Перебор всех вместимостей216,7 трлн · 25 дн.
Бинарный поиск по ответу259,5 млн · 2,6 с

Страница паттерна: когда его применять и шаблон на шести языках

По каким словам в задаче узнать приём?

  • «Минимальная скорость, чтобы успеть за h часов».
  • «Наименьшая вместимость корабля, чтобы вывезти груз за d дней».
  • «Разбить массив на k частей так, чтобы наибольшая сумма была минимальна».
  • «Расставить k коров в стойлах, чтобы минимальное расстояние было максимальным».

Сигнал это слово «минимум» или «максимум» рядом с условием. Проверить фиксированное значение легко. Найти лучшее значение напрямую трудно. Этот разрыв и закрывает приём. Перебор всех кандидатов подряд тоже сработает, но за O(n · R), где R это размер диапазона.

Как устроена функция проверки?

Проверка берёт кандидата и возвращает True, если он удовлетворяет условию. Она должна быть монотонной: раз True, то True и для всех больших кандидатов. Для задач на максимум наоборот.

Задача про Коко. Кандидат это скорость k. Часов нужно сумма ceil(куча / k) по всем кучам. Возвращаем True, если сумма не больше h. Быстрее скорость, меньше часов. Монотонно.

ЗадачаДиапазонПроверка(x)Ищем
Коко и бананы1 .. max(кучи)часов при скорости x <= hнаименьший True
Вместимость корабляmax(w) .. sum(w)дней при вместимости x <= dнаименьший True
Split Array Largest Summax(a) .. sum(a)частей с лимитом x <= kнаименьший True
Коровы в стойлах1 .. max разрывk коров на расстоянии x помещаютсянаибольший True

Как написать бинарный поиск по ответу на Python?

import math

def min_eating_speed(piles, h):
    lo, hi = 1, max(piles)

    def ok(k):
        return sum(math.ceil(p / k) for p in piles) <= h

    while lo < hi:
        mid = (lo + hi) // 2
        if ok(mid):
            hi = mid          # mid подходит, пробуем меньше
        else:
            lo = mid + 1      # mid не подходит, нужно больше
    return lo

# вариант на максимум: наибольший x, для которого ok(x) True
def largest_ok(lo, hi, ok):
    while lo < hi:
        mid = (lo + hi + 1) // 2
        if ok(mid):
            lo = mid
        else:
            hi = mid - 1
    return lo

Цикл держит в lo наименьшее значение, которое ещё может подойти. Когда lo догнал hi, это ответ. Плюс один во втором варианте спасает от бесконечного цикла.

Как это выглядит на примере?

Кучи [3, 6, 7, 11], h = 8. Диапазон от 1 до 11. Пробуем 6: часов 1 + 1 + 2 + 2 = 6, подходит, hi = 6. Пробуем 3: часов 1 + 2 + 3 + 4 = 10, много, lo = 4.

Пробуем 5: часов 1 + 2 + 2 + 3 = 8, подходит, hi = 5. Пробуем 4: часов тоже 8, подходит, hi = 4. lo равен hi. Ответ 4.

Четыре проверки вместо одиннадцати. При диапазоне до миллиарда будет тридцать проверок вместо миллиарда.

Как выбрать границы?

Нижняя граница это наименьшее осмысленное значение. Для скорости это 1. Для вместимости это самый тяжёлый предмет, иначе он не поедет вообще.

Верхняя граница это значение, которое точно подходит. Самая большая куча, сумма всех весов. Лишний запас стоит пары проверок, поэтому берите с запасом.

На каких ошибках ломается бинарный поиск по ответу?

  • Проверка не монотонна. Тогда половина с ответом выбрасывается.
  • Границы не включают ответ. Вместимость меньше самого тяжёлого груза его не увезёт.
  • mid = (lo + hi) // 2 в задаче на максимум. lo = mid тогда не сдвигается.
  • Целочисленное деление там, где нужно округление вверх.

Как объяснить приём на собеседовании?

Скажите: «Ответ напрямую не посчитать, но догадку я проверю за O(n)». Потом скажите, что проверка монотонна. Назовите границы. Пишите цикл.

Сложность назовите как O(n log(hi - lo)). Логарифм берётся от диапазона ответов, а не от массива. Собеседующие проверяют, что вы знаете, какой это логарифм.

Отработать узнавание приёма можно на странице бинарный поиск по ответу. Версия для массива лежит на странице бинарный поиск.

Вопросы и ответы

Чем это отличается от обычного бинарного поиска?

Обычный сравнивает mid с целью в отсортированном массиве. Этот вызывает на mid функцию проверки. Массив вообще может быть не отсортирован.

Где приём встречается вне собеседований?

В планировании нагрузки: сколько серверов нужно, чтобы очередь разгребалась за час. Проверить одно число серверов легко. Найти минимум напрямую сложно. Это та же задача про Коко с другими словами.

Может ли ответ быть дробным?

Да. Крутите цикл фиксированное число раз, около ста, вместо условия lo равен hi. Или остановитесь, когда hi - lo меньше нужной точности.

Как понять, что проверка монотонна?

Спросите себя: если значение x подходит, подойдёт ли x + 1? Для скорости, вместимости и лимита суммы ответ да. Если ответ «не всегда», приём не подходит, и нужен другой способ.

Что делать, если проверка стоит O(n log n)?

Тогда всего будет O(n log n log R). Обычно это проходит. Одна сортировка до цикла часто возвращает проверку к O(n).

Бесплатный урок: Угадать ответ и бинарно искать саму догадку Пишешь его сам прямо в браузере, аккаунт не нужен.