Учитывая отсортированный массив, найдите максимальный подмассив повторяющихся значений

95
11

Еще один вопрос о собеседовании попросил меня найти максимально возможный поднабор повторяющихся значений, учитывая отсортированный массив в кратчайшее возможное время.


Let input array be A[1 ... n]
Find an array B of consecutive integers in A such that:
for x in range(len(B)-1):
B[x] == B[x+1]

Я считаю, что лучший алгоритм делит массив пополам и идет от середины наружу и сравнивает из середины целые числа друг с другом и находит самое длинное напряжение одних и тех же целых чисел от середины. Затем я бы назвал метод рекурсивно, разделив массив пополам и вызывая метод на обеих половинах.


Мой интервьюер сказал, что мой алгоритм хорош, но мой анализ того, что алгоритм O (logn) неверен, но так и не дошел до того, чтобы сказать мне, что такое правильный ответ. Мой первый вопрос заключается в том, что такое Big-O-анализ этого алгоритма? (Покажите как можно больше работы, пожалуйста, Big-O не моя сильная сторона.) И мой второй вопрос исключительно для моего любопытства, есть ли еще более эффективный по времени алгоритм?

спросил(а) 2012-09-15T16:42:00+04:00 8 лет, 4 месяца назад
1
Решение
93

Лучшее, что вы можете сделать для этой проблемы, - это решение O(n), поэтому ваш алгоритм не может быть как правильным, так и O(lg n).


Рассмотрим, например, случай, когда массив не содержит повторяющихся элементов. Чтобы определить это, нужно изучить каждый элемент и изучить каждый элемент O(n).


Это простой алгоритм, который найдет самую длинную подпоследовательность повторяющегося элемента:

start = end = 0
maxLength = 0
i = 0
while i + maxLength < a.length:
if a[i] == a[i + maxLength]:
while i + maxLength < a.length and a[i] == a[i + maxLength]:
maxLength += 1
start = i
end = i + maxLength
i += maxLength

return a[start:end]


Если у вас есть основания полагать, что подпоследовательность будет длинной, вы можете установить начальное значение maxLength на какое-то эвристически выбранное значение, чтобы ускорить движение вещей, а затем искать только более короткие последовательности, если вы их не найдете ( т.е. вы получаете end == 0 после первого прохода.)

ответил(а) 2012-09-15T17:07:00+04:00 8 лет, 4 месяца назад
43

В этом алгоритме элементы n посещаются с постоянным количеством вычислений для каждого посещенного элемента, поэтому время работы O(n).


С учетом отсортированного массива A[1..n]:


max_start = max_end = 1
max_length = 1
start = end = 1
while start < n
while A[start] == A[end] && end < n
end++
if end - start > max_length
max_start = start
max_end = end - 1
max_length = end - start
start = end

ответил(а) 2012-09-15T17:42:00+04:00 8 лет, 4 месяца назад
44

Я думаю, мы все согласны с тем, что в худшем случае, когда все A уникальны или где все A одинаковы, вам нужно изучить каждый элемент массива, чтобы определить, нет ли дубликатов или определить весь массив содержит одно число. Как и другие плакаты, это будет O(N). Я не уверен, что разделение и победа помогут вам с алгоритмической сложностью на этом, хотя вы можете немного упростить код, используя рекурсию. Разделить и победить действительно помогает сократить Big O, когда вы можете выбросить большие части ввода (например, двоичный поиск), но в случае, когда вам потенциально нужно изучить все входные данные, это не будет сильно отличаться.


Я предполагаю, что результат заключается в том, что вы просто возвращаете размер самого большого B, который вы нашли, хотя вы можете легко изменить это, чтобы вместо этого вернуть B.

Итак, на фронте алгоритма, учитывая, что A отсортирован, я не уверен, что ответ будет более быстрым/более простым, чем просто ходить по массиву по порядку. Кажется, что самый простой ответ состоит в том, чтобы иметь 2 указателя, один начиная с индекса 0 и один начиная с индекса 1. Сравните их, а затем увеличивайте их оба; каждый раз, когда они одинаковы, вы указываете счетчик вверх, чтобы дать вам текущий размер B, и когда они отличаются от вас reset, который соответствует нулю. Вы также сохраняете переменную для максимального размера B, который вы нашли до сих пор, и обновляете ее каждый раз, когда вы найдете более крупный B.

ответил(а) 2012-09-15T17:38:00+04:00 8 лет, 4 месяца назад
-4

Предполагая, что наибольшие последовательные целые числа имеют только длину 1, вы будете сканировать весь массив A из n элементов. Таким образом, сложность не в терминах n, а в терминах len (B).


Не уверен, что сложность O (n/len (B)).


Проверка 2-кратного кейса


- Когда n == len (B), вы получаете мгновенный результат (только проверка A [0] и A [n-1]
- Когда n == 1, вы получаете O (n), проверяя все элементы
- Когда нормальный случай, я слишком ленив, чтобы написать алгоритм для анализа...


Edit


Учитывая, что len(B) не известно заранее, мы должны взять наихудший случай, т.е. O (n)

ответил(а) 2012-09-15T17:06:00+04:00 8 лет, 4 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема