Предположим, что у меня есть отсортированный список/массив. Мне нужно подсчитать количество отдельных чисел в этом списке/массиве в повторениях O (logN), которые я уже знаю, что мне нужно использовать какой-то бинарный алгоритм, но я не могу этого сделать в O (logN) повторения в худшем случае. Есть ли идея?
Используйте модуль bisect
.
import bisect as b
arr = [1, 1, 1, 2, 2, 3, 3, 3, 3]
for x in [1, 2, 3, 0]:
print(b.bisect_right(arr, x) - b.bisect_left(arr, x))
Выход:
3
2
4
0
Таким образом, алгоритм работает для любого значения, которое вы передаете ему. Если переданное значение отсутствует в списке, возвращается 0.
Модуль bisect
работает, используя двоичный поиск, чтобы найти подходящее место для вставки данного элемента. bisect_left
дает самый левый индекс, а bisect_right
дает индекс справа от любых существующих значений. Вычитая два, мы получаем количество значений x
уже присутствующих в списке.
Поскольку модуль bisect использует двоичный поиск, этот метод равен O (log N).
Вы можете разделить и покорить и вычесть подсчеты, когда последний элемент в первом тайме равен первому элементу во второй половине:
def count(l):
if len(l) <= 1:
return len(l)
mid = len(l) // 2
head, tail = l[:mid], l[mid:]
return count(head) + count(tail) - (len(head) and len(tail) and head[-1] == tail[0])
чтобы:
count([2,2,3,4,4,5,6,6,6,7,8])
возвращает: 7
(так как у нас есть 7 различных чисел: 2
, 3
, 4
, 5
, 6
, 7
, 8
)
n
вы хотите знать, сколько раз это встречается в списке? Список отсортирован? Первая проблема не может быть решена в O (log n), просто имея упорядоченный список. Последнее, если список упорядочен, вы можете просто использовать два варианта бинарного поиска, который дает вам первый индексi
и последний индексj
где этот элемент найден, и у вас естьji
- число вхождений.