Это не использует линейное хеширование, но работает быстрее, чем O (N):
- Выберите некоторое небольшое количество C и использовать алгоритм перебора, чтобы найти первый дубликат для первых элементов C массива. Очистите первые элементы C, если ничего не найдено.
- Выполняйте оставшиеся шаги с пустыми первыми N элементами. Первоначально N = C. После каждой итерации N удваивается.
- Последовательно добавьте числа из индексов N + 1 .. 3 * N/2 в хэш-таблицу в элементах первого N массива. Используйте открытую адресацию. После перемещения всех элементов N/2 коэффициент хэш-нагрузки должен быть равен 1/2. Прозрачное пространство, занятое N/2 элементами, которые мы только что переместили. Для следующих элементов N/4 выполните поиск каждого из них в хэш-таблице (таблицах), построенных до сих пор, затем помещаем их в пространство, которое всегда вдвое больше числа элементов. Продолжайте это до тех пор, пока элементы массива N-C не будут хэшированы. Найдите остальные элементы C в хэш-таблицах и сравните их друг с другом.
- Теперь у нас есть N элементов массива без дубликатов, занимающих пространство 2 * N. Повторите их на месте.
- Последовательно найдите все остальные элементы массива в этой хеш-таблице. Затем очистите эти элементы 2 * N, установите N = 2 * N и переходите к шагу 3.
Шаги 3..5 могут быть упрощены. Просто хэш-элементы N + 1 .. 3 * N/2 и найдите все остальные элементы массива в этой хэш-таблице. Тогда сделайте то же самое для элементов 3 * N/2 + 1 .. 2 * N. Это в два раза медленнее, чем исходный алгоритм, но в то же время O (N log N).
Другой альтернативой является использование первых N пустых элементов для построения двоичного дерева поиска для элементов N + 1 .. 3 * N/2 и поиск всех остальных элементов массива в этом дереве. Тогда сделайте то же самое для элементов 3 * N/2 + 1 .. 2 * N. (Это работает только в том случае, если массив достаточно мал, и его элементы могут быть проиндексированы целыми значениями).
Алгоритм, описанный выше, является вероятностным и в среднем работает в O (N log N) времени. Его наихудшей сложностью является O (N). Альтернатива с деревом двоичного поиска может иметь O (N log N) наихудшая сложность, если дерево самобалансируется. Но это сложно. Задачу можно выполнить в O (N log N) наихудшее время с более простым алгоритмом.
Этот алгоритм последовательно выполняет итерацию через массив и сохраняет следующий инвариант: наибольшая возможная подматрица с размером, которая имеет силу два, которая находится слева от текущей позиции, начинается с индекса 0 и сортируется; следующая такая подматрица следует за ним и также сортируется; и т. д. Другими словами, двоичное представление текущего индекса описывает, как много отсортированных подмассивов предшествует ему. Например, для индекса 87 (1010111) мы имеем один элемент в индексе 86, сортированную пару в индексе 84, отсортированную подматрицу из 4 элементов в 80, отсортированную подматрицу из 16 элементов в 64 и отсортированную sub-array из 64 элементов в начале массива.
- Итерация через массив
- Поиск текущий элемент во всех предыдущих подмассивах с помощью двоичного поиска.
- Сортируйте текущий элемент вместе с предшествующими подматрицами, которые соответствуют концевым «единицам» в двоичном представлении текущего индекса. Например, для индекса 87 (1010111) нам нужно отсортировать текущий элемент вместе с тремя подмассивами (1 + 1 + 2 + 4 = 8 элементов). Этот шаг позволяет добавлять текущий элемент в подматрицы, сохраняя инвариант алгоритма.
- Продолжить следующей итерации шага 1.
Первые 3 слова в описании тега "interview-questions" ... НЕ ИСПОЛЬЗУЙТЕ. – Aaron
Считаете ли вы возможным улучшить время O (n)? – esej
Сортируйте массив на месте с помощью quicksort? –