Недавно я посетил интервью, где меня попросили «написать программу, чтобы найти 100 самых больших чисел из массива в 1 миллиард чисел».
Я смог дать только решение методом грубой силы, которое должно было отсортировать массив за O (nlogn) сложность времени и взять последние 100 чисел.
Arrays.sort(array);
Интервьюер искал лучшую временную сложность, я попробовал несколько других решений, но не смог ответить на него. Есть ли лучшее решение сложности времени?
O(1)
в этом случае, потому что нет увеличения размера. Интервьюер должен был спросить «Как найти m самых больших элементов из массива n с n >> m?».Ответы:
Вы можете сохранить приоритетную очередь из 100 самых больших чисел, перебирать миллиардные числа, всякий раз, когда вы встречаете число, большее, чем наименьшее число в очереди (заголовок очереди), удаляете заголовок очереди и добавляете новый номер. в очередь.
РЕДАКТИРОВАТЬ: как отметил Dev, с приоритетной очереди, реализованной с кучей, сложность вставки в очередь
O(logN)
В худшем случае вы получите что лучше, чем
billionlog2(100)
billion
log2(billion)
В общем, если вам нужны самые большие числа K из набора из N чисел, сложность
O(NlogK)
скорее, чемO(NlogN)
, это может быть очень значительным, когда K очень мало по сравнению с N.EDIT2:
Ожидаемое время этого алгоритма довольно интересно, поскольку на каждой итерации вставка может происходить или не происходить. Вероятность того, что i-ое число будет вставлено в очередь, - это вероятность того, что случайная величина будет больше, чем, по крайней мере,
i-K
случайные переменные из того же распределения (первые k чисел автоматически добавляются в очередь). Мы можем использовать статистику заказов (см. Ссылку ), чтобы рассчитать эту вероятность. Например, давайте предположим, что числа были случайным образом выбраны равномерно{0, 1}
, ожидаемое значение (iK) -ого числа (из числа i) равно(i-k)/i
, и вероятность того, что случайная величина будет больше этого значения, равна1-[(i-k)/i] = k/i
.Таким образом, ожидаемое количество вставок составляет:
И ожидаемое время работы может быть выражено как:
(
k
время для генерации очереди с первымиk
элементами, затемn-k
сравнений и ожидаемого количества вставок, как описано выше, каждая занимает среднееlog(k)/2
время)Обратите внимание , что при
N
очень большой по сравнению сK
, это выражение намного ближе кn
чемNlogK
. Это несколько интуитивно понятно, так как в случае вопроса даже после 10000 итераций (что очень мало по сравнению с миллиардом) вероятность того, что число будет вставлено в очередь, очень мала.источник
k
постоянным и маленьким по сравнению сn
. Хотя всегда следует помнить об этих «нормальных обстоятельствах».Если об этом спрашивают во время интервью, я думаю, что интервьюер, вероятно, хочет видеть ваш процесс решения проблем, а не только ваши знания алгоритмов.
Описание довольно общее, поэтому, возможно, вы сможете задать ему диапазон или значение этих чисел, чтобы прояснить проблему. Это может произвести впечатление на интервьюера. Если, например, эти цифры соответствуют возрасту людей внутри страны (например, Китая), то это гораздо более простая проблема. С разумным допущением, что никто не старше 200 лет, вы можете использовать массив int размером 200 (может быть, 201) для подсчета числа людей одного возраста за одну итерацию. Здесь индекс означает возраст. После этого это кусок пирога, чтобы найти 100 наибольшее число. Кстати, этот алгоритм называется счетной сортировкой .
В любом случае, сделать интервью более конкретным и понятным - это хорошо для вас.
источник
Вы можете перебирать числа, которые занимают O (n)
Всякий раз, когда вы найдете значение, превышающее текущий минимум, добавьте новое значение в круговую очередь размером 100.
Минут этой круговой очереди - ваше новое значение сравнения. Продолжайте добавлять в эту очередь. Если заполнено, извлеките минимум из очереди.
источник
Я понял, что это помечено как «алгоритм», но выбрасывает некоторые другие варианты, поскольку, вероятно, также следует пометить «интервью».
Каков источник 1 миллиарда чисел? Если это база данных, тогда «выбор значения из порядка таблиц по значению desc limit 100» вполне бы сработал - могут быть различия в диалектах.
Это одноразовое или что-то, что будет повторяться? Если повторяется, как часто? Если это одноразовый файл и данные находятся в файле, то 'cat srcfile | сортировать (варианты по необходимости) | head -100 'позволит вам быстро выполнять продуктивную работу, за которую вам платят, в то время как компьютер справляется с этой тривиальной работой.
Если это будет повторяться, вы посоветуете выбрать любой достойный подход, чтобы получить первоначальный ответ и сохранить / кэшировать результаты, чтобы вы могли непрерывно иметь возможность сообщать о первых 100.
Наконец, есть это соображение. Вы ищете работу начального уровня и проводите собеседования с вычурным менеджером или будущим коллегой? Если это так, то вы можете отказаться от всех подходов, описывающих относительные технические плюсы и минусы. Если вы ищете более управленческую работу, то подходите к ней так, как это сделал бы менеджер, связанный с затратами на разработку и обслуживание решения, и говорите «большое спасибо», и уходите, если интервьюер хочет сосредоточиться на мелочах CS , У него и у вас вряд ли будет большой потенциал продвижения вперед.
Удачи на следующем интервью.
источник
Моей непосредственной реакцией на это было бы использование кучи, но есть способ использовать QuickSelect, не сохраняя все входные значения под рукой одновременно.
Создайте массив размером 200 и заполните его первыми 200 входными значениями. Запустите QuickSelect и откажитесь от низких 100, оставив вам 100 свободных мест. Прочитайте следующие 100 входных значений и снова запустите QuickSelect. Продолжайте до тех пор, пока вы не выполните все входные данные партиями по 100 штук.
В конце у вас есть лучшие 100 значений. Для значений N вы запустили QuickSelect примерно N / 100 раз. Стоимость каждого Quickselect примерно в 200 раз превышает некоторую постоянную, поэтому общая стоимость в 2N раза превышает постоянную. Это выглядит линейно по размеру входных данных для меня, независимо от размера параметра, который я собираюсь установить равным 100 в этом объяснении.
источник
partial_sort
работает непосредственно с набором данных из 200 миллионов 32-битных данныхint
(созданным через MT19937, равномерно распределенным).Ordering.greatestOf(Iterable, int)
делает Гуава . Это абсолютно линейное и однопроходное время, и это очень симпатичный алгоритм. К тому же, у нас также есть некоторые фактические критерии: его постоянные коэффициенты на несколько медленнее, чем традиционная очередь с приоритетами в среднем случае, но эта реализация намного более устойчива к «худшему» вводу (например, строго восходящий ввод).Вы можете использовать алгоритм быстрого выбора, чтобы найти число по индексу (по порядку) [billion-101], а затем выполнить итерацию по числам и найти числа, которые больше этого числа.
Время этого алгоритма: 2 XO (N) = O (N) (средняя производительность по случаю)
Второй вариант, предложенный Томасом Юнгблутом :
Использование кучного строительство MAX кучи будет принимать O (N), то топ 100 Макс число будет находиться в верхней части кучи, все , что вам нужно , это получить их из кучи (100 XO (Log (N)).
Время этого алгоритма: O (N) + 100 XO (Log (N)) = O (N)
источник
O(N)
, выполнение двух быстрых выборок и еще одного линейного сканирования требует больше затрат, чем необходимо.100*O(N)
(если это правильный синтаксис) =O(100*N)
=O(N)
(предположительно, 100 может быть переменной, если это так, это не совсем верно). Да, и Quickselect имеет худшую производительность O (N ^ 2) (ой). И если он не помещается в память, вы будете дважды перезагружать данные с диска, что намного хуже, чем один раз (это узкое место).Хотя другое решение для быстрого выбора было отклонено, факт остается фактом, что быстрый выбор найдет решение быстрее, чем использование очереди размером 100. У быстрого выбора есть ожидаемое время выполнения 2n + o (n), с точки зрения сравнений. Очень просто реализация будет
Это займет 3n + o (n) сравнений в среднем. Более того, это можно сделать более эффективным, используя тот факт, что быстрый выбор оставит 100 самых больших элементов в массиве в 100 самых правых местах. Таким образом, время выполнения может быть улучшено до 2n + o (n).
Существует проблема, что, как ожидается, время работы, а не худший случай, но с использованием стратегии приличной выбора поворота (например, выбрать 21 элементов в случайном порядке, и выбрать медиану этих 21 в качестве оси), то число сравнений может быть гарантируется с высокой вероятностью не более (2 + c) n для сколь угодно малой постоянной c.
Фактически, используя оптимизированную стратегию выборки (например, выборку элементов sqrt (n) случайным образом и выбор 99-го процентиля), время работы может быть уменьшено до (1 + c) n + o (n) для сколь угодно малого c (при условии, что K, количество элементов, которые будут выбраны, o (n)).
С другой стороны, использование очереди размером 100 потребует O (log (100) n) сравнений, а база журналов 2 из 100 приблизительно равна 6,6.
Если мы подумаем об этой проблеме в более абстрактном смысле, выбирая самые большие элементы K из массива размера N, где K = o (N), но оба K и N уходят в бесконечность, тогда время работы версии быстрого выбора будет O (N) и версия очереди будет O (N log K), поэтому в этом смысле быстрый выбор также асимптотически превосходит.
В комментариях упоминалось, что решение очереди будет запущено в ожидаемое время N + K log N на случайном входе. Конечно, предположение о случайном вводе никогда не будет действительным, если вопрос не сформулирован явно. Можно было бы решить проблему очереди, чтобы обойти массив в случайном порядке, но это потребует дополнительных затрат на N вызовов генератора случайных чисел, а также либо перестановки всего входного массива, либо выделения нового массива длиной N, содержащего случайные показатели
Если проблема не позволяет перемещаться по элементам в исходном массиве, а стоимость выделения памяти высока, поэтому дублирование массива не вариант, это другой вопрос. Но строго с точки зрения времени работы, это лучшее решение.
источник
возьмите первые 100 номеров миллиарда и рассортируйте их. Теперь просто переберите миллиард, если номер источника больше, чем наименьшее из 100, вставьте в порядке сортировки. То, что вы в итоге получите, будет намного ближе к O (n) по размеру набора.
источник
Два варианта:
(1) куча (приоритетная очередь)
Поддерживайте минимальную кучу размером 100. Пройдите через массив. Как только элемент станет меньше первого элемента в куче, замените его.
(2) Карта-уменьшенная модель.
Это очень похоже на пример подсчета слов в hadoop. Задание на карте: подсчитайте частоту или время каждого элемента. Уменьшить: получить верхний элемент К.
Обычно я бы дал рекрутеру два ответа. Дайте им все, что они хотят. Конечно, кодирование с уменьшением карты будет трудоемким, потому что вы должны знать все точные параметры. Не вредно практиковать это. Удачи.
источник
Очень простым решением было бы перебрать массив 100 раз. Который
O(n)
.Каждый раз, когда вы вытаскиваете наибольшее число (и меняете его значение на минимальное значение, чтобы вы не видели его на следующей итерации или не отслеживали индексы предыдущих ответов (отслеживая индексы, исходный массив может иметь кратно одному и тому же номеру)). После 100 итераций вы получите 100 самых больших чисел.
источник
Вдохновленный ответом @ron teller, вот программа на Си, которая делает то, что вы хотите.
На моей машине (ядро i3 с быстрым SSD) это занимает 25 секунд и 1724 сортировки. Я создал двоичный файл
dd if=/dev/urandom/ count=1000000000 bs=1
для этого запуска.Очевидно, есть проблемы с производительностью при чтении только 4 байтов за раз - с диска, но это ради примера. С положительной стороны, очень мало памяти требуется.
источник
Самое простое решение состоит в том, чтобы сканировать массив из миллиарда чисел и хранить 100 самых больших значений, найденных до сих пор, в небольшом буфере массива без какой-либо сортировки и запоминать наименьшее значение этого буфера. Сначала я подумал, что этот метод был предложен fordprefect, но в комментарии он сказал, что он предполагает реализацию структуры данных из 100 чисел в виде кучи. Всякий раз, когда обнаруживается новое число, которое больше минимума в буфере, перезаписывается новым найденным значением, и в буфере снова выполняется поиск текущего минимума. Если числа в массиве миллиардов случайным образом распределены большую часть времени, значение из большого массива сравнивается с минимумом маленького массива и отбрасывается. Только для очень очень маленькой доли числа значение должно быть вставлено в маленький массив. Таким образом, разница в манипулировании структурой данных с небольшими числами может быть проигнорирована. Для небольшого числа элементов трудно определить, является ли использование очереди приоритетов на самом деле более быстрым, чем использование моего наивного подхода.
Я хочу оценить количество вставок в небольшой буфер массива из 100 элементов при сканировании массива из 10 ^ 9 элементов. Программа сканирует первые 1000 элементов этого большого массива и должна вставить в буфер не более 1000 элементов. Буфер содержит 100 элементов из 1000 отсканированных элементов, то есть 0,1 отсканированного элемента. Итак, мы предполагаем, что вероятность того, что значение из большого массива больше текущего минимума буфера, составляет около 0,1. Такой элемент должен быть вставлен в буфер. Теперь программа сканирует следующие 10 ^ 4 элементов из большого массива. Потому что минимум буфера будет увеличиваться каждый раз, когда вставляется новый элемент. Мы подсчитали, что соотношение элементов больше нашего текущего минимума составляет около 0,1, и поэтому для вставки требуется 0,1 * 10 ^ 4 = 1000 элементов. На самом деле ожидаемое количество элементов, которые вставляются в буфер, будет меньше. После сканирования этих 10 ^ 4 элементов доля чисел в буфере составит около 0,01 от сканированных элементов. Поэтому при сканировании следующих 10 ^ 5 чисел мы предполагаем, что в буфер будет вставлено не более 0,01 * 10 ^ 5 = 1000. Продолжая эту аргументацию, мы вставили около 7000 значений после сканирования 1000 + 10 ^ 4 + 10 ^ 5 + ... + 10 ^ 9 ~ 10 ^ 9 элементов большого массива. Таким образом, при сканировании массива с 10 ^ 9 элементами случайного размера мы ожидаем не более 10 ^ 4 (= 7000 округленных) вставок в буфер. После каждой вставки в буфер должен быть найден новый минимум. Если буфер представляет собой простой массив, нам нужно 100 сравнений, чтобы найти новый минимум. Если буфер представляет собой другую структуру данных (например, кучу), нам нужно как минимум 1 сравнение, чтобы найти минимум. Чтобы сравнить элементы большого массива, нам нужно 10 ^ 9 сравнений. Таким образом, в целом нам нужно примерно 10 ^ 9 + 100 * 10 ^ 4 = 1.001 * 10 ^ 9 сравнений при использовании массива в качестве буфера и как минимум 1.000 * 10 ^ 9 сравнений при использовании другого типа структуры данных (например, кучи) , Таким образом, использование кучи приносит только 0,1% прироста, если производительность определяется числом сравнений. Но какова разница во времени выполнения между вставкой элемента в кучу из 100 элементов и заменой элемента в массиве из 100 элементов и поиском его нового минимума? 000 * 10 ^ 9 сравнений при использовании другого типа структуры данных (например, кучи). Таким образом, использование кучи приносит только 0,1% прироста, если производительность определяется числом сравнений. Но какова разница во времени выполнения между вставкой элемента в кучу из 100 элементов и заменой элемента в массиве из 100 элементов и поиском его нового минимума? 000 * 10 ^ 9 сравнений при использовании другого типа структуры данных (например, кучи). Таким образом, использование кучи приносит только 0,1% прироста, если производительность определяется числом сравнений. Но какова разница во времени выполнения между вставкой элемента в кучу из 100 элементов и заменой элемента в массиве из 100 элементов и поиском его нового минимума?
На теоретическом уровне: сколько сравнений необходимо для вставки в кучу. Я знаю, что это O (log (n)), но насколько велик постоянный фактор? я
На уровне машины: как кэширование и прогноз ветвления влияют на время выполнения вставки кучи и линейного поиска в массиве.
На уровне реализации: Какие дополнительные затраты скрыты в структуре данных кучи, предоставляемой библиотекой или компилятором?
Я думаю, что это некоторые из вопросов, на которые необходимо ответить, прежде чем можно будет попытаться оценить реальную разницу между производительностью кучи из 100 элементов или массива из 100 элементов. Поэтому имеет смысл провести эксперимент и измерить реальную производительность.
источник
Алгоритм Самые большие x элементов из n:
Я назову возвращаемое значение LIST . Это набор элементов x (по моему мнению, это должен быть связанный список)
Итак, каков наихудший сценарий?
x log (x) + (nx) (log (x) +1) = nlog (x) + n - x
Так что это O (N) время для худшего случая. +1 - это проверка, если число больше, чем наименьшее число в LIST. Ожидаемое время для среднего случая будет зависеть от математического распределения этих n элементов.
Возможные улучшения
Этот алгоритм может быть немного улучшен для наихудшего сценария, но IMHO (я не могу доказать это утверждение), который ухудшит среднее поведение. Асимптотическое поведение будет таким же.
Улучшение в этом алгоритме будет заключаться в том, что мы не будем проверять, больше ли элемент, чем наименьший. Для каждого элемента мы попытаемся вставить его, и если он меньше наименьшего, мы проигнорируем его. Хотя это звучит нелепо, если мы рассмотрим только худший сценарий, который у нас будет
x log (x) + (nx) log (x) = nlog (x)
операции.
Для этого варианта использования я не вижу дальнейших улучшений. И все же вы должны спросить себя - что, если мне придется делать это больше, чем log (n) раз и для разных x-es? Очевидно, что мы отсортировали бы этот массив в O (n log (n)) и взяли бы наш элемент x всякий раз, когда они нам нужны.
источник
На этот вопрос будет дан ответ со сложностью N log (100) (вместо N log N) всего одной строкой кода C ++.
Окончательным ответом будет вектор, в котором первые 100 элементов гарантированно будут 100 самыми большими числами вашего массива, а остальные элементы неупорядочены.
C ++ STL (стандартная библиотека) очень удобен для решения подобных задач.
Примечание: я не говорю, что это оптимальное решение, но оно спасло бы ваше интервью.
источник
Простым решением будет использование очереди с приоритетами, добавление первых 100 чисел в очередь и отслеживание наименьшего числа в очереди, затем итерация по другим миллиардам чисел, и каждый раз, когда мы находим одно, которое больше, чем наибольшее число в очереди с приоритетами мы удаляем наименьшее число, добавляем новый номер и снова отслеживаем наименьшее число в очереди.
Если бы числа были в случайном порядке, это было бы прекрасно, потому что, поскольку мы перебираем миллиард случайных чисел, очень редко будет следующее число среди 100 самых больших до сих пор. Но цифры могут быть не случайными. Если массив уже отсортирован в порядке возрастания, то мы всегда вставляем элемент в очередь с приоритетами.
Поэтому сначала мы выбираем, скажем, 100 000 случайных чисел из массива. Чтобы избежать случайного доступа, который может быть медленным, мы добавим, скажем, 400 случайных групп из 250 последовательных чисел. Благодаря этому случайному выбору мы можем быть совершенно уверены, что очень немногие из оставшихся чисел входят в первую сотню, поэтому время выполнения будет очень близко к времени простого цикла, сравнивающего миллиард чисел с некоторым максимальным значением.
источник
Поиск лучших 100 из миллиарда номеров лучше всего сделать с помощью min-heap из 100 элементов.
Сначала заполните мин-кучу первыми 100 встреченными числами. min-heap будет хранить наименьшее из первых 100 чисел в корне (вверху).
Теперь, когда вы идете вдоль остальных чисел, сравните их только с корнем (наименьшее из 100).
Если обнаруженное новое число больше, чем корень из min-heap, замените корень на это число, иначе проигнорируйте его.
Как часть вставки нового числа в min-heap наименьшее число в куче придет к вершине (root).
После того, как мы пройдем все числа, у нас будут самые большие 100 чисел в минимальной куче.
источник
Я написал простое решение на Python на случай, если кому-то будет интересно. Он использует
bisect
модуль и временный список возврата, который он сохраняет отсортированным. Это похоже на реализацию очереди с приоритетами.Использование с 100 000 000 элементов и вводом в худшем случае, который представляет собой отсортированный список:
Для расчета 100 000 000 элементов потребовалось около 40 секунд, поэтому я боюсь сделать это за 1 миллиард. Чтобы быть справедливым, хотя, я кормил его вводом наихудшего случая (по иронии судьбы массив, который уже отсортирован).
источник
Я вижу много O (N) обсуждений, поэтому я предлагаю что-то другое только для упражнения мысли.
Есть ли известная информация о природе этих чисел? Если это случайный характер, то не идите дальше и посмотрите на другие ответы. Вы не получите лучшие результаты, чем они.
Тем не мение! Посмотрите, заполняет ли какой-либо механизм заполнения списков этот список в определенном порядке. Находятся ли они в четко определенной схеме, в которой вы можете точно знать, что наибольшая величина чисел будет найдена в определенной области списка или в определенном интервале? Там может быть образец для этого. Если это так, например, если они гарантированно находятся в каком-то нормальном распределении с характерным горбом в середине, всегда имеют повторяющиеся восходящие тренды среди определенных подмножеств, имеют продолжительный всплеск в некоторый момент времени T в середине данных Например, это может быть случай инсайдерской торговли или отказа оборудования, или, может быть, просто иметь «всплеск» для каждого N-го числа, так как при анализе сил после катастрофы вы можете значительно сократить количество проверяемых записей.
В любом случае, есть пища для размышлений. Может быть, это поможет вам дать будущим интервьюерам вдумчивый ответ. Я знаю, что был бы впечатлен, если бы кто-то задал мне такой вопрос в ответ на такую проблему - это бы сказало мне, что они думают об оптимизации. Просто признайте, что не всегда есть возможность оптимизировать.
источник
Создать пустой список из 100 пустых слотов
Для каждого номера в списке ввода:
Если число меньше первого, пропустите
В противном случае замените его на этот номер
Затем нажмите номер через смежный обмен; пока он не станет меньше следующего
Вернуть список
Примечание: если
log(input-list.size) + c < 100
, то оптимальным способом является сортировка списка ввода, а затем разбить первые 100 элементов.источник
Сложность O (N)
Сначала создайте массив из 100 дюймов, инициализируйте первый элемент этого массива как первый элемент из N значений, отследите индекс текущего элемента с помощью другой переменной, назовите его CurrentBig
Итерация по значениям N
когда закончите, выведите массив M из CurrentBig 100 раз по модулю 100 :-) Для ученика: убедитесь, что последняя строка кода не превосходит правильные данные перед выходом кода
источник
Другой алгоритм O (n) -
Алгоритм находит наибольшее 100 по исключению
Рассмотрим все миллионы чисел в их двоичном представлении. Начните с самого значительного бита. Выяснение, является ли MSB 1, может быть сделано умножением логической операции с соответствующим числом. Если в этих миллионах более 100 единиц, то остальные цифры с нулями исключают. Теперь из оставшихся чисел перейдем к следующему наиболее значимому биту. вести подсчет количества оставшихся чисел после исключения и продолжать до тех пор, пока это число больше 100.
Основная логическая операция может выполняться параллельно на графических процессорах.
источник
Я бы выяснил, у кого было время собрать миллиард чисел в массив и уволить его. Должен работать на правительство. По крайней мере, если бы у вас был связанный список, вы могли бы вставить число в середину, не сдвигая полмиллиарда, чтобы освободить место. Еще лучше Btree позволяет бинарный поиск. Каждое сравнение устраняет половину вашей суммы. Алгоритм хеширования позволил бы вам заполнить структуру данных как шахматную доску, но не так хорошо для разреженных данных. Лучше всего иметь массив решений из 100 целых чисел и отслеживать минимальное число в массиве решений, чтобы вы могли заменить его, когда натолкнетесь на большее число в исходном массиве. Вам нужно будет посмотреть на каждый элемент в исходном массиве, предполагая, что он не отсортирован с самого начала.
источник
Вы можете сделать это
O(n)
вовремя. Просто перебирайте список и отслеживайте 100 самых больших чисел, которые вы видели в любой заданной точке, и минимальное значение в этой группе. Когда вы обнаружите, что новое число больше наименьшего из ваших десяти, замените его и обновите новое минимальное значение 100 (может потребоваться постоянное время, равное 100, чтобы определить это каждый раз, когда вы это делаете, но это не влияет на общий анализ ).источник
Управление отдельным списком - это дополнительная работа, и вам придется перемещаться по всему списку каждый раз, когда вы найдете другую замену. Просто выполните сортировку и возьмите топ-100.
источник
Пожалуйста, обратите внимание esp. второй шаг может быть легко вычислен параллельно! И это также будет эффективно, когда вам нужен миллион самых больших элементов.
источник
Это вопрос от Google или других гигантов отрасли. Возможно, следующий код - правильный ответ, ожидаемый вашим интервьюером. Стоимость времени и стоимость пространства зависят от максимального числа во входном массиве. Для 32-битного ввода массива int, максимальная стоимость пространства составляет 4 * 125M байт, стоимость времени составляет 5 * млрд.
источник
я сделал свой собственный код, не уверен, что это то, что "интервьюер" это смотрит
источник
Возможные улучшения.
Если файл содержит 1 миллиардное число, чтение может быть очень долгим ...
Чтобы улучшить эту работу вы можете:
источник
Сначала возьмите 1000 элементов и добавьте их в максимальную кучу. Теперь возьмите первые 100 элементов и сохраните их где-нибудь. Теперь выберите следующие 900 элементов из файла и добавьте их в кучу вместе с последними 100 самыми старшими элементами.
Продолжайте повторять этот процесс, собирая 100 элементов из кучи и добавляя 900 элементов из файла.
Окончательный выбор из 100 элементов даст нам максимум 100 элементов из миллиарда чисел.
источник
Задача: Найти m наибольших элементов из n элементов, где n >>> m
Самое простое решение, которое должно быть очевидно для всех, - это просто выполнить m проходов алгоритма сортировки пузырьков.
затем распечатайте последние n элементов массива.
Это не требует внешних структур данных и использует алгоритм, который всем известен.
Оценка времени работы O (m * n). Наилучшие ответы на данный момент - это O (n log (m)), так что это решение не намного дороже для малых m.
Я не говорю, что это не может быть улучшено, но это, безусловно, самое простое решение.
источник