Задача состоит в том, чтобы найти алгоритм O (1) длины N необходимого списка чисел. Так что не имеет значения, если вам нужны первые 100 или 10000 номеров, время вставки должно быть O (1).
Хитрость заключается в том, что хотя требование O (1) упомянуто для вставки списка, в вопросе ничего не сказано о порядке времени поиска во всем числовом пространстве, но оказывается, что это можно сделать O (1) также. Решение тогда следующее:
Организовать хеш-таблицу с номерами для ключей и парами связанных списков указателей для значений. Каждая пара указателей является началом и концом последовательности связанных списков. Обычно это будет просто один элемент, затем следующий. Каждый элемент в связанном списке идет рядом с элементом со следующим наибольшим номером. Таким образом, связанный список содержит отсортированную последовательность требуемых номеров. Сохраните запись с наименьшим номером.
Возьмите новое число x из случайного потока.
Это выше, чем последнее записанное наименьшее число? Да => Шаг 4, Нет => Шаг 2
Нажмите на хэш-таблицу с только что взятым номером. Есть ли запись? Да => Шаг 5. Нет => Возьмите новый номер x-1 и повторите этот шаг (это простой линейный поиск вниз, просто потерпите меня здесь, это можно улучшить, и я объясню как)
С элементом списка, только что полученным из хеш-таблицы, вставьте новый номер сразу после элемента в связанном списке (и обновите хеш)
Возьмите наименьшее записанное число l (и удалите его из хэша / списка).
Нажмите на хэш-таблицу с только что взятым номером. Есть ли запись? Да => Шаг 8. Нет => Возьмите новое число l + 1 и повторите этот шаг (это простой линейный поиск вверх)
При положительном попадании число становится новым самым низким числом. Перейти к шагу 2
Чтобы учесть дублирующиеся значения, хешу фактически необходимо поддерживать начало и конец последовательности связанного списка элементов, которые являются дубликатами. Таким образом, добавление или удаление элемента в данном ключе увеличивает или уменьшает указанный диапазон.
Вставка здесь - O (1). Упомянутые поиски, я думаю, что-то вроде, O (средняя разница между числами). Средняя разница увеличивается с размером пространства чисел, но уменьшается с требуемой длиной списка чисел.
Таким образом, стратегия линейного поиска довольно плохая, если числовое пространство велико (например, для 4-байтового типа int, от 0 до 2 ^ 32-1) и N = 100. Чтобы обойти эту проблему производительности, вы можете сохранить параллельные наборы хеш-таблиц, где числа округляются до более высоких величин (например, 1 с, 10 с, 100 с, 1000 с), чтобы получить подходящие ключи. Таким образом, вы можете увеличивать и уменьшать скорость, чтобы быстрее выполнять требуемые поиски. Я думаю, что производительность становится O (логарифмический диапазон), который является постоянным, то есть O (1) также.
Чтобы сделать это более понятным, представьте, что у вас есть номер 197 на руках. Вы попали в хэш-таблицу 10 с '190', она округляется до ближайшей десятки. Что-нибудь? Нет. Таким образом, вы понижаетесь в 10 с, пока не нажмете, скажем, 120. Затем вы можете начать с 129 в хэш-таблице 1 с, затем пробовать 128, 127, пока не нажмете что-нибудь. Теперь вы нашли, где в связанном списке вставить число 197. При его вставке необходимо также обновить хеш-таблицу 1 с записью 197, хеш-таблицу 10 с числом 190, 100 с 100 и т. Д. Большинство шагов Вы когда-либо должны сделать здесь в 10 раз журнал диапазона номеров.
Возможно, я ошибся в некоторых деталях, но так как это обмен программистами, а контекстом были интервью, я надеюсь, что вышеизложенное является достаточно убедительным ответом для такой ситуации.
РЕДАКТИРОВАТЬ Я добавил некоторые дополнительные детали, чтобы объяснить схему параллельной хеш-таблицы и то, как это означает, что упомянутые мной плохие линейные поиски могут быть заменены поиском O (1). Я также понял, что, конечно, нет необходимости искать следующий наименьший номер, потому что вы можете перейти прямо к нему, посмотрев в хеш-таблицу с наименьшим номером и перейдя к следующему элементу.