2013-10-09 2 views
0

Я борюсь с моей домашней работой и нуждаюсь в небольшом нажатии - вопрос заключается в том, чтобы разработать алгоритм, который в O (nlogm) позволит найти несколько наименьших элементов 1<k1<k2<...<kn, и у вас есть m * k. Я знаю, что простой алгоритм выбора принимает o (n) время для поиска k-го элемента, но как вы уменьшаете m в своем повторении? Я хотя бы делал и k1 и kn в каждом прогоне, но это выведет только 2, а не m/2.Как найти несколько наименьших элементов ki в массиве?

Поблагодарите несколько поручений.

+0

Возможный дубликат [Напишите программу, чтобы найти 100 самых больших чисел из массива из 1 миллиарда чисел] (http://stackoverflow.com/questions/19227698/write-a-program-to-find-100-largest -numbers-out-of-of-of-a-array-of-1-billion-numbers) – Dukeling

+1

Я нахожу, что ваш запрос проблемы действительно запутан. Что такое 'm'? Почему вы используете little-oh в 'o (n)'? – NPE

+0

Спасибо, что 100 самых больших проблем с номерами очень похожи. Но я не вижу, как они придумывают nlogm tim. @NPE M - это в основном число ki, которое нам нужно, чтобы не было необходимости, если нам нужны 1, 2 и 3 наименьшие числа, m = 3. – user2067051

ответ

2

Если я правильно понял вопрос, у вас есть вектор K, содержащий m индексов, и вы хотите найти k-й ранжированный элемент A для каждого k из K. Если K содержит наименьшие m индексов (т. Е. k = 1,2, ..., m), то это легко можно сделать в линейном времени T = O (n), используя quickselect для нахождения элемента k_m (так как все меньшие элементы будут слева в конце Быстрый выбор). Поэтому я предполагаю, что K может содержать любой набор из m индексов.

Один из способов добиться этого - запустив quickselect на всех К одновременно. Вот алгоритм

QuickselectMulti(A,K) 
If K is empty, then return an empty result set 
Pick a pivot p from A at random 
Partition A into sets A0<p and A1>p. 
i = A0.size + 1 
if K contains i, then remove i from K and add (i=>p) to the result set. 
Partition K into sets K0<i and K1>i 
add QuickselectMulti(A0,K0) to the result set 
subtract i from each k in K1 
call QuickselectMulti(A1,K1), add i to each index of the output, and add this to the result set 
return the result set 

Если K содержит только один элемент, это то же самое, что и рандомизированное quickselect. Чтобы понять, почему время работы в среднем равно O (n log m), сначала подумайте, что произойдет, когда каждая точка разворота точно разделяет как A, так и K пополам. В этом случае вы получите два рекурсивных вызовов, так что у вас есть

T = n + 2T(n/2,m/2) 
    = n + n + 4T(n/4,m/4) 
    = n + n + n + 8T(n/8,m/8) 

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

On edit: Анализ этого алгоритма может сделать это проще, выбирая ось вращения, запустив p = Quickselect (A, k_i), где k_i - средний элемент K, а не выбор p случайным образом. Это гарантирует, что K будет разделяться пополам каждый раз, поэтому количество рекурсивных вызовов будет точно соответствовать журналу m, а так как quickselect работает в линейном времени, результат будет по-прежнему равен O (n log m).

+0

Спасибо, человек, что мне нужно! извините за плохие объяснения. Только один вопрос, почему? Почему каждый раз сокращается пополам? – user2067051

+0

Каждый раз m разрезается на две части m1 и m2, так что m1 + m2 = m (или m1 + m2 = m-1, если индекс i принадлежит K). Они соответствуют двум подмножествам K1 и K2 группы K, разделенным индексом i. Как я уже сказал, вы не можете предположить, что K будет точно сокращаться пополам каждый раз, поэтому у вас есть еще одна работа, но если вы пройдете расчеты, вы обнаружите, что ожидаемое время работы все равно будет O (n log m). – mrip

+0

Подумайте об этом, вы можете сделать это проще, выбрав p, запустив p = Quickselect (A, k_i), где k_i - средний элемент K. Это гарантирует, что K будет разделяться пополам каждый раз, и поэтому число рекурсивных вызовов будет точно log m. – mrip

Смежные вопросы