Как найти k ближайших соседей к медиане n различных чисел в O (n) времени?

Я могу использовать медиану алгоритма выбора медиан, чтобы найти медиану в O(n). Кроме того, я знаю, что после выполнения алгоритма все элементы слева от медианы меньше медианы, а все элементы справа больше медианы. Но как найти k ближайших соседей к медиане в O(n) времени?

Если медиана равна n, то числа слева меньше n, а числа справа больше n. Однако массив не сортируется с левой или правой стороны. Числа-это любой набор различных чисел, заданных пользователем.

проблема заключается во введении в алгоритмы Кормена, задача 9.3-7

11 ответов


кажется, ни у кого этого нет. Вот как это сделать. Сначала найдите медиану, как описано выше. Это O (n). Теперь припаркуйте медиану в конце массива и вычитайте медиану из каждого другого элемента. Теперь найдите элемент K массива (не включая последний элемент), снова используя алгоритм быстрого выбора. Это не только находит элемент k (по порядку), но и оставляет массив так, что самые низкие K чисел находятся в начале массива. Это ближе к среднему, как только вы добавите медиану обратно.


медиана медиан, вероятно, не очень помогает в поиске ближайших соседей, по крайней мере для большого n. Правда, каждый столбец из 5 секционирован вокруг медианы, но этого недостаточно для решения проблемы.

Я бы просто рассматривал медиану как промежуточный результат и рассматривал ближайших соседей как проблему очереди приоритетов...

Как только у вас есть медиана от медианы медианы медианы, обратите внимание на ее значение.

выполнить алгоритм heapify для всех ваших данных-см. Википедия-Бинарная Куча. В сравнениях результат базируется на разнице относительно сохраненного медианного значения. Наиболее приоритетными являются позиции с наименьшим АБС (значение - медиана). Для этого требуется O(n).

первый элемент массива теперь является медианой (или ее дубликатом), и массив имеет структуру кучи. Используйте алгоритм извлечения кучи, чтобы вытащить столько ближайших соседей, сколько вам нужно. Это O (K log n) для k ближайший сосед.

пока k является константой, вы получаете o(n) медиану медиан, O(n) heapify и O(log n) extracting, давая o (n) в целом.


med=Select(A,1,n,n/2)   //finds the median

for i=1 to n
   B[i]=mod(A[i]-med)

q=Select(B,1,n,k) //get the kth smallest difference

j=0
for i=1 to n
   if B[i]<=q 
     C[j]=A[i] //A[i], the real value should be assigned instead of B[i] which is only the difference between A[i] and median.
       j++
return C

вы можете решить свою проблему так:

вы можете найти медиану в O (n), w.г. используя алгоритм O(n) nth_element.

цикл по всем элементам substutiting каждый с парой:

the absolute difference to the median, element's value. 

еще раз вы делаете nth_element с n = k. после применения этого алгоритма вы гарантированно будете иметь k наименьших элементов в абсолютной разнице сначала в новом массиве. Вы берете их индексы и готово!


вы можете использовать сортировку без сравнения, например сортировку radix, в списке чисел L, затем найдите k ближайших соседей, рассмотрев окна k элементов и изучив конечные точки окна. Другой способ заявить "найти окно" - найти i, который минимизирует abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i] - L[n/2]) (Если K нечетно) или abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+1] - L[n/2]) (Если K четно). Комбинируя случаи,abs(L[(n-k)/2+i] - L[n/2]) + abs(L[(n+k)/2+i+!(k&1)] - L[n/2]). Простой, O (k) способ найти минимум-начать с i=0, затем скользить влево или вправо, но вы должны быть в состоянии найти минимум in O (log (k)).

выражение, которое вы минимизируете, происходит от преобразования L в другой список, M, принимая разницу каждого элемента от медианы.

m=L[n/2]
M=abs(L-m)

i минимизирует M[n/2-k/2+i] + M[n/2+k/2+i].


вы уже знаете, как найти медиану в O(n)

если порядок не имеет значения, выбор K наименьших можно сделать в O (n) применитесь для K наименьшего к rhs медианы и K наибольшего к lhs медианы

из Википедии

 function findFirstK(list, left, right, k)
 if right > left
     select pivotIndex between left and right
     pivotNewIndex := partition(list, left, right, pivotIndex)
     if pivotNewIndex > k  // new condition
         findFirstK(list, left, pivotNewIndex-1, k)
     if pivotNewIndex < k
         findFirstK(list, pivotNewIndex+1, right, k)

Не забудьте особый случай, когда k==n возвращает исходный список


на самом деле, ответ довольно прост. Все, что нам нужно сделать, это выбрать k элементов с наименьшими абсолютными различиями от медианы, движущейся от m-1 до 0 и m+1 до n-1, когда медиана находится в индексе m. Мы выбираем элементы, используя ту же идею, что и при объединении 2 отсортированных массивов.


Четыре Шага:

  1. сначала найдите медианы (медиана медиана) - O (n)
  2. определите абсолютную разницу между медианой и каждым из элементов-O (n)
  3. используйте алгоритм наименьшего элемента kth для получения результата (Quickselect) - O (n)
  4. теперь нам нужно выбрать K ближайший из массива-O (n)

Если вы знаете индекс медианы, который должен быть просто ceil (array.length/2) может быть, тогда это просто должен быть процесс перечисления n(x-k), n (x-k+1), ... , n(x), n(x+1), n (x+2), ... n(x+k) где N-массив, x-индекс медианы, а k-количество необходимых соседей.(возможно, k / 2, Если вы хотите всего k, а не K с каждой стороны)


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

на каждом шаге этого дополнительного прогона через список необходимы шаги O(k), и поскольку K является постоянным, Это O(1). Так что итог за время для дополнительного запуска требуется O (n), как и общее время выполнения полного алгоритма.


поскольку все элементы различны, могут быть элементы atmost 2 с тем же отличием от среднего. Я думаю, что мне проще иметь 2 массива A[k] и B[k] индекс, представляющий абсолютное значение разницы от среднего. Теперь задача состоит в том, чтобы просто заполнить массивы и выбрать k элементов, прочитав первые k непустых значений массивов, читающих A[i] и B[i] перед A[i+1] и B[i+1]. Это можно сделать за O(n) время.