Лучший алгоритм удаления дубликатов в массиве строк

сегодня в школе учитель попросил нас реализовать алгоритм удаления дубликатов. Это не так сложно, и все придумали следующее решение (псевдокод):

for i from 1 to n - 1
    for j from i + 1 to n
        if v[i] == v[j] then remove(v, v[j])    // remove(from, what)
    next j
next i

вычислительная сложность для этого algo является n(n-1)/2. (Мы в старшей школе, и мы не говорили о big-O, но, кажется,O(n^2)). Это решение кажется уродливым и, конечно же, медленным, поэтому я попытался закодировать что-то быстрее:

procedure binarySearch(vector, element, *position)
    // this procedure searches for element in vector, returning
    // true if found, false otherwise. *position will contain the
    // element's place (where it is or where it should be)
end procedure

----

// same type as v
vS = new array[n]

for i from 1 to n - 1
    if binarySearch(vS, v[i], &p) = true then
        remove(v, v[i])
    else
        add(vS, v[i], p)      // adds v[i] in position p of array vS
    end if
next i

таким образом vS будет содержат все элементы, которые мы уже прошли. Если элемент v[i] находится в этом массиве, затем он дублируется и удаляется. Вычислительная сложность для бинарного поиска -log(n) и для основного цикла (второй фрагмент) составляет n. Поэтому весь CC n*log(n) если я не ошибаюсь.

тогда у меня была другая идея об использовании двоичного дерева, но я не могу его опустить.
В основном мои вопросы:

  • правильно ли мой расчет CC? (а если нет, почему?)
  • есть ли более быстрый способ для этого?

спасибо

5 ответов


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

затем проверить его еще раз. Во время этого сканирования просто исключите последовательные идентичные элементы.

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

Если его там нет, добавьте его. Если он там, удалите его из массива.

обратите внимание, что это займет некоторую дополнительную память, и хэширование будет иметь постоянный фактор, который способствует вашей среде выполнения. Хотя сложность времени лучше, практическая среда выполнения будет только onyl быстрее, как только вы превысите определенный размер массива


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

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


add is O(n), поэтому ваш расчет CC неверен. Ваш алгоритм O(n^2).

более того, как бы remove будет осуществляться? Также похоже, что это будет O(n) - таким образом, начальный алгоритм будет O(n^3).


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


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

// You have 
{"a", "ab", "b", "ab", "a", "c", "cd", "cd"}, 

// you break it into 
{"a", "b", "a", "c"} and {"ab", "ab", "cd", "cd"}, 

// remove duplicates from those arrays using the merge method that others have mentioned, 
// and then combine the arrays back together into 
{"a", "b", "c", "ab", "cd"}