Завдання чітко - знайти алгоритм, який є 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. Щоб обійти цю проблему з продуктивністю, ви можете зберегти паралельні набори хештелів, де числа округляються до більших величин (наприклад, 1s, 10s, 100s, 1000s), щоб зробити відповідні ключі. Таким чином ви можете підняти зусилля вгору та вниз, щоб швидше виконати потрібні пошуки. Після цього продуктивність стає O (часовий діапазон журналу), я думаю, що це постійне, тобто O (1) також.
Щоб зробити це зрозумілішим, уявіть, що у вас є номер 197. Ви потрапили в хеш-таблицю 10s, на якій було написано '190', вона округляється до найближчої десятки. Що-небудь? Ні. Отже, ви спускаєтесь через 10 с, поки не натиснете скажімо 120. Потім ви можете почати з 129 у хештейлі 1s, потім спробуйте 128, 127, поки щось не вдарить. Тепер ви знайшли, куди у зв'язаному списку потрібно вставити число 197. Поки ви вводите його, ви також повинні оновити хешблет 1s із записом 197, хешблет 10s з номером 190, 100s зі 100 тощо. Найбільш кроки Ви коли-небудь повинні робити це в 10 разів більше журналу діапазону чисел.
Я, можливо, помилився з деякими деталями, але, оскільки це обмін програмістами, а контекст інтерв'ю, я би сподівався, що сказане є достатньо переконливою відповіддю для такої ситуації.
EDIT Я додав сюди додаткову деталізацію, щоб пояснити паралельну схему хештелю та як це означає, що я згадував поганий лінійний пошук, який можна замінити на пошук O (1). Я також зрозумів, що, звичайно, не потрібно шукати наступне найнижче число, тому що ви можете перейти до нього прямо, заглянувши в хешбл з найменшим числом і перейшовши до наступного елемента.