Во-первых, давайте попробуем определить диапазон, в котором k
может быть как можно меньше. Мы будем смотреть на элементы a[0], a[1], a[2], ... a[2 ** i], ...
, пока не найдем элемент, который больше k
. Предположим, мы остановились на индексе r
. Тогда мы точно знаем, что, поскольку массив отсортирован, если k
находится в массиве, его позиция m
меньше r
. Другим фактом, который имеет решающее значение для сложности времени, является то, что m > i/2
. Это верно, потому что на предыдущем шаге мы смотрели на a[r/2]
, и оно было меньше, чем k
.
Если мы запустим простой двоичный поиск для подмассива a[0 ... r]
, мы найдем k
в O(log r)
. Общее количество шагов для поиска r
было O(log r)
. Так как r > m > r/2
это правда, что log r > log m > log r - 1
. Поэтому мы можем переписать O(log r)
как O(log m)
, и это именно то, что нам нужно.
Это мое решение в Python 3:
def find(a, k):
if a[0] > k:
return -1
r = 1
while r < len(a):
if a[r] > k:
break
r *= 2
if r >= len(a):
if a[-1] < k:
return -1
r = len(a) - 1
l = -1
while r - l > 1:
m = (l + r) // 2
if a[m] < k:
l = m
else:
r = m
if a[r] == k:
return r
else:
return -1