4.9 KiB
Поиск границ с использованием двоичного поиска
Поиск левой границы
!!! question
Дан упорядоченный массив `nums` длиной $n$, который может содержать повторяющиеся элементы. Необходимо вернуть индекс самого левого элемента `target` в массиве. Если массив не содержит этот элемент, вернуть $-1$.
Вспомним метод поиска точки вставки с использованием двоичного поиска: после завершения поиска i указывает на самый левый target, поэтому поиск точки вставки по сути является поиском индекса самого левого target.
Рассмотрим реализацию поиска левой границы через функцию поиска точки вставки. Обратите внимание, что массив может не содержать target, что может привести к следующим двум результатам:
- Индекс точки вставки
iвыходит за границы массива. - Элемент
nums[i]не равенtarget.
При возникновении любой из этих двух ситуаций можно просто вернуть -1. Код приведен ниже:
[file]{binary_search_edge}-[class]{}-[func]{binary_search_left_edge}
Поиск правой границы
Как же найти самый правый target? Самый прямой способ -- изменить код, заменив операцию сужения указателей в случае nums[m] == target. Код здесь опущен, заинтересованные читатели могут реализовать его самостоятельно.
Ниже мы рассмотрим два более изящных метода.
Повторное использование поиска левой границы
На самом деле мы можем использовать функцию поиска самого левого элемента для поиска самого правого элемента, конкретный метод: преобразовать поиск самого правого target в поиск самого левого target + 1.
Как показано на рисунке ниже, после завершения поиска указатель i указывает на самый левый target + 1 (если он существует), а j указывает на самый правый target, поэтому достаточно вернуть j.
Обратите внимание, что возвращаемая точка вставки -- это i, поэтому необходимо вычесть из нее 1, чтобы получить j:
[file]{binary_search_edge}-[class]{}-[func]{binary_search_right_edge}
Преобразование в поиск элемента
Мы знаем, что когда массив не содержит target, в конечном итоге i и j будут указывать соответственно на первый элемент, больший и меньший target.
Поэтому, как показано на рисунке ниже, мы можем создать элемент, которого не существует в массиве, для поиска левой и правой границ.
- Поиск самого левого
target: можно преобразовать в поискtarget - 0.5и вернуть указательi. - Поиск самого правого
target: можно преобразовать в поискtarget + 0.5и вернуть указательj.
Код здесь опущен, следует отметить следующие два момента:
- Данный массив не содержит дробных чисел, что означает, что нам не нужно беспокоиться о том, как обрабатывать случай равенства.
- Поскольку этот метод вводит дробные числа, необходимо изменить тип переменной
targetв функции на тип с плавающей точкой (в Python изменения не требуются).

