Мы возьмем набор данных, украсим каждый элемент подписью, и сортируем его. Подпись имеет свойство, что сортировка будет группировать эти элементы вместе, которые могут имеют дубликаты. Когда сравнивает data_set [j] с элементами в data_set [j + 1 ...], когда первая подпись в [j + 1 ...] дублирует проверку, мы продвигаем i. Этот «критерий смежности» гарантирует, что нам не нужно смотреть дальше; Ни один элемент за пределами этого не может быть дубликатом.
Это значительно уменьшает сравнение O (N^2). Сколько я дам , аналитик алгоритма решает, но приведенный ниже код делает ~ 400k сравнения вместо 100 м наивного O (N^2).
Подпись начинается с разбивки элементов. Мы разделим диапазон чисел на N конусов равного размера: 1..k, k + 1..2k, 2k + 1..3k, ... При повторении по элементам мы увеличиваем счетчик, если число попадает в конкретное ведро. Это дает начальную подпись формы (0,0,0,1,3,0,0, ... 4,2).
Сигнатура обладает тем свойством, что если
sum(min(sig_a[i], sig_b[i]) for i in range(10)) >= 5
то есть возможные элементы, связанные с подписями имеют по крайней мере 5duplicates. Но больше, если вышесказанное делает не hold, , тогда элементы не могут иметь 5 дубликатов. Позволяет называть это «критерием соответствия подписи».
Но, сортировка по вышеуказанной подписи делает не имеет свойство смежности , упомянутое выше. Однако, если мы изменяем подпись, чтобы иметь форму два элемента:
(sum(sig[:-1]), sig[-1])
тогда «подпись критерий соответствия» держит. Но выполняется ли критерий смежности ? Да. Сумма этой подписи составляет 10.Если мы перечисления, мы имеем следующие возможные подписи:
(0,10) (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1) (10,0)
Если мы сравним (0,10) против (1,9) .. (10,0), мы отмечаем, что раз тест подписи он больше не повторится. Критерий смежности имеет место. Кроме того, этот критерий смежности выполняется для всех положительных значений, а не только для «5».
Хорошо, но разбивка подписи на два больших ведра не обязательно приведет к уменьшению поиска O (N^2); подпись является чрезмерно общей. Мы решаем, что проблему путем создания подписи для сиг [: - 1], продуцирующие
(sum(sig[:-1]), sig[-1]), (sum(sig[:-2]), sig[-2]), ...
и так далее. Я считаю, что эта подпись все еще удовлетворяет смежности, но Я мог ошибаться.
Есть некоторые оптимизации, которых я не делал: для подписи требуется только последнее значение каждого кортежа, а не первое, но необходимо будет пересмотреть шаг сортировки. Кроме того, сравнение может быть оптимизировано с ранним сбоем, когда становится ясно, что дальнейшее сканирование не может быть выполнено.
# python 3.0
import random
# M number of elements, N size of each element
M = 10000
N = 10
# Bounds on the size of an element of each set
Vmin,Vmax = 0, (1 << 12)
# DupCount is number of identical numbers required for a duplicate
DupCount = 5
# R random number generator, same sequence each time through
R = random.Random()
R.seed(42)
# Create a data set of roughly the correct size
data_set = [list(s) for s in (set(R.randint(Vmin, Vmax) for n in range(N)) for m in range(M)) if len(s) == N]
# Adorn the data_set signatures and sort
def signature(element, width, n):
"Return a signature for the element"
def pearl(l, s):
def accrete(l, s, last, out):
if last == 0:
return out
r = l[last]
return accrete(l, s-r, last-1, out+[(s-r,r)])
return accrete(l, s, len(l)-1, [])
l = (n+1) * [0]
for i in element:
l[i // width] += 1
return pearl(l, len(element))
# O(n lg(n)) - with only 10k elements, lg(n) is a little over 13
adorned_data_set = sorted([signature(element, (Vmax-Vmin+1)//12, 12), element] for element in data_set)
# Count the number of possible intersections
def compare_signatures(sig_a, sig_b, n=DupCount):
"Return true if the signatures are compatible"
for ((head_a, tail_a), (head_b, tail_b)) in zip(sig_a, sig_b):
n -= min(tail_a, tail_b)
if n <= 0:
return True
return False
k = n = 0
for i, (sig_a, element_a) in enumerate(adorned_data_set):
if not element_a:
continue
for j in range(i+1, len(adorned_data_set)):
sig_b, element_b = adorned_data_set[j]
if not element_b:
continue
k += 1
if compare_signatures(sig_a, sig_b):
# here element_a and element_b would be compared for equality
# and the duplicate removed by adorned_data_set[j][1] = []
n += 1
else:
break
print("maximum of %d out of %d comparisons required" % (n,k))
Hm, известен ли диапазон чисел? В вашем примере можно предположить, что используются только числа от 1 до 10000 или около того, если это правда, у меня есть идея, как это решить. – Lucero
Мы говорим о эффективности времени, эффективности пространства или обоим? –
Я думаю, что в основном эффективность времени, так как это, кажется, требование здесь. – Lucero