Интервью-вопрос
Какая алгоритмическая сложность у бинарного поиска
Бинарный поиск работает за O(log n) по уже отсортированному массиву. На интервью важно сразу назвать условие отсортированности, стоимость подготовки данных и ограничения структуры данных.
- Добавлен
- Редакция
Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.
Мини-квиз
Проверка перед разбором
Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.
Вопрос 1 из 60 правильно
Разбор
Разобраться, а не зазубрить
Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.
Базовая идея
Бинарный поиск работает не так, как линейный. Вы не проверяете элементы один за другим. Вы берете середину отсортированного диапазона, сравниваете ее с искомым значением и понимаете, в какой половине продолжать поиск.
Поэтому число шагов растет медленно. Для 16 элементов в худшем случае нужно около 4 делений диапазона. Для 1 000 000 элементов нужно около 20 шагов. В этом смысл O(log n): при удвоении размера данных добавляется примерно один шаг.
Как это звучит на интервью
Хороший короткий ответ может быть таким:
У бинарного поиска временная сложность O(log n), если массив отсортирован. На каждом шаге мы сравниваем target с элементом в середине и отбрасываем половину диапазона. Дополнительная память в итеративной реализации O(1). Если массив надо сначала сортировать, стоимость сортировки считается отдельно.
Так лучше, чем просто назвать O(log n). Вы показываете, что понимаете условие корректности и не забываете про реальную стоимость решения.
Реализация на JavaScript
Базовая итеративная реализация выглядит так:
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (arr[mid] === target) {
return mid;
}
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}Важны две детали. Во-первых, массив должен быть отсортирован по тому же правилу, по которому вы сравниваете значения. Во-вторых, границы нужно сдвигать за mid, иначе на некоторых входах цикл может не закончиться.
Подготовка данных во frontend
Если список пришел с API, не считайте его отсортированным без контракта. Неверное предположение может привести к тихому багу: UI покажет, что элемент не найден, хотя он есть в данных.
В React не сортируйте массив из state или props на месте:
// Плохо: sort мутирует исходный массив
const sorted = items.sort((a, b) => a.price - b.price);Такой код может изменить данные, которые уже использует другой компонент. Безопаснее сначала сделать копию. Если список большой и сортировка нужна для каждого поиска, подготовьте массив один раз для конкретной версии данных:
const sortedItems = useMemo(
() => [...items].sort((a, b) => a.price - b.price),
[items],
);Это не отменяет стоимость сортировки, но убирает лишнюю работу на каждом рендере и не ломает исходный порядок данных в UI.
Как выбрать подход на практике
Когда бинарный поиск уместен
Бинарный поиск подходит, ожидаем O(log n).Чаще проще O(n), сортировка ради одного запроса может быть дороже.Можно один раз отсортировать или построить индекс, затем искать быстрее.Бинарный поиск обычно не дает выгоды без быстрого доступа к середине.Во frontend-задачах бинарный поиск встречается не только в учебных примерах. Вы можете использовать его для поиска позиции в отсортированном списке дат, ближайшего breakpoint, виртуализации длинного списка или работы с заранее подготовленными справочниками.
Но если у вас короткий список в UI, который меняется после каждого ответа сервера, бинарный поиск может быть лишним усложнением. В таком случае лучше выбрать решение, которое проще поддерживать и которое не ломает данные.
Где теряется O(log n)
- 1Проверить, что данные отсортированы по тому же ключу
- 2Держать границы left и right
- 3Сравнить target с серединой
- 4Сузить диапазон в нужную сторону
- 5Вернуть индекс или -1, когда диапазон пуст
- 1Искать в неотсортированном массиве
- 2Менять границы так, что middle повторяется
- 3Не учитывать дубликаты, если нужна граница
- 4Забыть, что сортировка тоже стоит времени
- 5Считать, что O(log n) верно для любой структуры данных
Самая частая ловушка: назвать O(log n) без условий. Если данные не отсортированы, бинарный поиск не становится просто медленнее. Он становится некорректным.
Еще одна ловушка: считать только поиск и забыть подготовку. Если вы ради одного поиска сортируете массив, итоговая стоимость будет примерно O(n log n) для сортировки и O(log n) для поиска. Это может быть хуже обычного прохода O(n).
Дубликаты и границы
Обычный бинарный поиск возвращает индекс найденного элемента, но при дубликатах это не обязательно первый или последний индекс. Если задача требует найти первую позицию, нужно продолжать поиск влево после совпадения.
function lowerBound(arr, target) {
let left = 0;
let right = arr.length;
while (left < right) {
const mid = Math.floor(left + (right - left) / 2);
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}Такой вариант возвращает позицию первого элемента, который не меньше target. Это полезно, когда нужно найти место вставки или левую границу диапазона.
Практический вывод
На интервью держите ответ в три шага. Сначала назовите сложность: O(log n). Затем объясните причину: каждый шаг делит диапазон пополам. После этого добавьте ограничения. Данные должны быть отсортированы, доступ к середине должен быть быстрым, а стоимость сортировки нужно считать отдельно.
Если хотите усилить ответ, сравните с линейным поиском. Для одного поиска по неотсортированным данным O(n) может быть разумнее. Для многих поисков по одному отсортированному массиву бинарный поиск обычно выигрывает.
Частые ошибки
Где обычно ошибаются
Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.
- 1
Забыть про отсортированность
Бинарный поиск не просто ускоряет поиск, он опирается на порядок данных. Если список пришел с API без гарантированной сортировки, алгоритм может вернуть неверный результат. Безопаснее явно сортировать данные или использовать линейный поиск, если сортировка не нужна дальше. - 2
Не считать стоимость сортировки
ОтветO(log n)верен для поиска по уже отсортированному массиву. Если вы сначала делаетеsort, общая стоимость для одного поиска обычно будетO(n log n). На интервью стоит отделять стоимость подготовки данных от стоимости самого поиска. - 3
Сказать, что алгоритм всегда быстрее
Для маленьких массивов разница может быть незаметна, а код бинарного поиска сложнее и легче ломается на границах. Во фронтенде это важно для простых списков в UI, где читаемость иногда важнее микрооптимизации. Сильнее звучит ответ: бинарный поиск выгоден на больших или многократно используемых отсортированных данных. - 4
Ошибиться в обновлении границ
Если после сравнения не сдвинутьleftилиrightзаmid, цикл может стать бесконечным. Правило простое: когдаarr[mid] < target, следующий диапазон начинается сmid + 1, иначе заканчивается наmid - 1для обычного поиска. - 5
Игнорировать дубликаты
Обычная реализация возвращает какое-то найденное вхождение, но не обязана вернуть первое или последнее. Если задача про диапазон цен, даты или позицию вставки, нужна модификация вроде lower bound. Иначе UI может подсветить не тот элемент или неверно посчитать диапазон. - 6
Мутировать массив из state или props
array.sort()меняет массив на месте. В React это может незаметно изменить state или props, сломать мемоизацию и дать странный порядок элементов в UI. Безопаснее делать копию:[...items].sort(compare), а для больших списков считать ее вuseMemoпо явным зависимостям.
Follow-up
Что могут спросить дальше
Короткие ответы на вопросы, которыми проверяют понимание сложности, ограничений и реализации бинарного поиска.
Живые ответы
Видео с похожим вопросом
Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.
Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.
Что такое бинарный поиск 😎
Бинарный поиск ищет значение в отсортированных данных, каждый шаг отбрасывает половину диапазона и работает за O(log n). Разбираем условия применения, границы цикла и типичные ошибки реализации на JavaScript.
Есть ли требования к массиву, передаваемому на вход в функцию бинарного поиска 😎
Бинарный поиск работает корректно только при строгом порядке данных и быстром доступе по индексу. Разбираем, как ответить на интервью, где ломается алгоритм и какие проверки важны во frontend-коде.