3

Как эффективно найти ранг каждого элемента массива, усредняя в случае связей? Например:Эффективное обнаружение рангов элементов в массиве?

float[] rank(T)(T[] input) { 
    // Implementation 
} 

auto foo = rank([3,6,4,2,2]); // foo == [3, 5, 4, 1.5, 1.5] 

Единственный способ, которым я могу думать делать это требует выделения 3 массива:

  1. дубликат входного массива, так как он должен быть отсортирован, и мы не его владельцем.
  2. Массив для отслеживания порядка сортировки входного массива.
  3. Множество рангов для возврата.

Кто-нибудь знает, как это сделать в O (N log N) и O (1) вспомогательном пространстве (что означает, что мы должны выделить только один массив, который мы собираемся вернуть) или по крайней мере, избавиться от одного из трех массивов выше?

+0

Что вы подразумеваете под «мы не владеем им»? – Jacob

+3

Фактически вы, вероятно, могли бы обойтись без второго массива, так как поиск в отсортированном массиве равен O (log N), и вам понадобятся N поисковых запросов, которые работают в соответствии с требованием O (N log N). –

+0

«мы его не владеем» = это функция библиотеки, которая должна предположить, что вызывающий агент rank() не ожидает, что его входной массив будет беспорядочно переупорядочен, поэтому по принципу наименьшего удивления мы должны его дублировать и сортировать по копии. – dsimcha

ответ

4

можно выделить массив, который вы собираетесь вернуться (назовем его R), инициализировать его 0..n-1, а затем «сортировать» входящий массив (называемый I), но используя сравнение I [R [k]] против I [R [j]] вместо нормального R [k] против R [j], а затем заменяя значения в массиве R как (вместо значений в массиве I, как обычно).

Вы можете реализовать эту косвенную сортировку, используя либо quicksort, либо heapsort (или bubblesort, но это испортит вашу сложность).

Вам нужно всего лишь выделить один массив - и некоторое пространство стека для индексов.

+0

Так очевидно, оглядываясь назад. Почему я не подумал об этом? – dsimcha

+1

Собственно, поразмыслив, это не сработает. Я изначально неправильно понял это. – dsimcha

+0

Да, так оно и есть - вам нужно косвенно сравнивать, а затем обновлять также косвенный массив. Я добавил разъяснение на свой пост. – florin

0

Если вы не владеете массивом, я не думаю, что это возможно сделать в O (N log N) и в пространстве O (1).

Если диапазон элементов (насколько большой элемент может быть) мал, используйте подсчет. Подсчитайте, сколько из них существует, и затем вычислите массив результатов на основе входного массива с использованием массива подсчета.

c - is counting result, 
C - is cumulative counting 
C[i] = c[i] + c[i-1] + c[i-2] + ... + c[0] 
result[i] = 1/c[in[i]] + C[in[i]-1] 
0

Почему бы не просто скопировать и отсортировать массив и перейти оттуда? Существует множество доступных алгоритмов сортировки на месте, таких как heapsort.

2

Итак, вы дублируете свой входной массив в foo. Сортировка foo на месте в O (n log n) с heapsort. Теперь возьмите первый элемент вашего входного массива и найдите его ранг в foo в O (log n), используя binary search и вставьте ранг в массив ranks и верните его.

Теперь вы используете 2 массивы вместо 3.

0

Возможно, было бы полезно суммировать florin's answer (и связанные с ним комментарии) с помощью простого кода.

Вот как сделать это в Ruby:

arr = [5,1,0,3,2,4] 
ranks = (0..arr.length-1).to_a.sort_by{ |x| arr[x] } 
# ranks => [2, 1, 4, 3, 5, 0] 

И в Python:

arr = [5,1,0,3,2,4] 
ranks = range(len(arr)) 
ranks.sort(key=lambda x:arr[x]) 
# ranks => [2, 1, 4, 3, 5, 0] 

Массив ранги говорит вам, что 0 имеет ранг 2, 1 имеет ранг 1, 2 имеет ранг 4 и т. д. (Конечно, эти ранги начинаются с нуля, а не с одного.)

+0

Этот метод не работает для отрицательных элементов массива: попробуйте с arr = [5,1,0,3, -2,4] - вы получите [4, 2, 1, 3, 5, 0] – florin

0

Как насчет использования двоичного дерева поиска и вставки элементов один за другим в этот BST. Ранг можно определить, сохранив счетчик на всех элементах, появляющихся слева от узла элемента, который мы хотим найти в ранге использования. Для перехода к BST.

0

Я использовал это для этого быстро и грязно в питоне:

def rank(X): 
    B = X[:] 
    B.sort() 
    return [ float(B.index(x)+1) for x in X] 

def rank(X): 
    B = X[:] 
    B = list(set(B)) 
    B.sort() 
    return [ float(B.index(x)+1) for x in X] 

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

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