Вы можете использовать структуру данных, что делает ее более эффективной для выполнения слияния. Здесь вы создаете нечто вроде противоположного дерева. Таким образом, в вашем примере вы сначала создали бы число перечисленных:
1 2 3 4 5 8 10
Теперь, если вы перебрать (1,2)
кортежа, вы смотрите 1
и 2
в каком-то словаре. Ищешь их предков (их нет здесь), а затем вы создаете какой-то слияния узла:
1 2 3 4 5 8 10
\/
12
Далее мы сливаться (1,3)
так мы смотрим предок 1
(12
) и 3
(3
) и выполнить другое слияние:
1 2 3 4 5 8 10
\/ |
12/
\/
123
Далее мы сливаться (2,4)
и (5,8)
и (8,10)
:
1 2 3 4 5 8 10
\/ | | \/ |
12/ | 58/
\/ / \/
123/ 5810
\/
1234
Вы также сохраняете список «слитных головок», чтобы вы могли легко вернуть элементы.
Времени, чтобы получить в свои руки грязные
Так что теперь мы знаем, как построить такую структуру данных, давайте реализуем один.Сначала определим узел:
class Merge:
def __init__(self,value=None,parent=None,subs=()):
self.value = value
self.parent = parent
self.subs = subs
def get_ancestor(self):
cur = self
while cur.parent is not None:
cur = cur.parent
return cur
def __iter__(self):
if self.value is not None:
yield self.value
elif self.subs:
for sub in self.subs:
for val in sub:
yield val
Теперь мы первый инициализирует словарь для каждого элемента в списке:
vals = set(x for tup in array for x in tup)
и создать словарь для каждого элемента в vals
, отображающей на Merge
:
dic = {val:Merge(val) for val in vals}
и merge_heads
:
merge_heads = set(dic.values())
Теперь для каждого кортежа в массиве, мы LookUp соответствующего Merge
объекта, который является предок, мы создаем новый Merge
поверх этого, удалите две старых головы из merge_head
набора и добавить новый merge
к нему:
for frm,to in array:
mra = dic[frm].get_ancestor()
mrb = dic[to].get_ancestor()
mr = Merge(subs=(mra,mrb))
mra.parent = mr
mrb.parent = mr
merge_heads.remove(mra)
merge_heads.remove(mrb)
merge_heads.add(mr)
Наконец после того, как мы сделали, что мы можем просто построить set
для каждого Merge
в merge_heads
:
resulting_sets = [set(merge) for merge in merge_heads]
и resulting_sets
будет (порядок может различаться):
[{1, 2, 3, 4}, {8, 10, 5}]
Собираем все вместе (без class
определения):
vals = set(x for tup in array for x in tup)
dic = {val:Merge(val) for val in vals}
merge_heads = set(dic.values())
for frm,to in array:
mra = dic[frm].get_ancestor()
mrb = dic[to].get_ancestor()
mr = Merge(subs=(mra,mrb))
mra.parent = mr
mrb.parent = mr
merge_heads.remove(mra)
merge_heads.remove(mrb)
merge_heads.add(mr)
resulting_sets = [set(merge) for merge in merge_heads]
Это будет худший случай работать в О (п) , но вы можете баланс дерево такое, что предок находится в O (log n) вместо этого, делая его O (n log n). Кроме того, вы можете короткое замыкание список предков, что делает его еще быстрее.
Вы никогда - AFAIK - никогда не избавиться, по крайней мере, одну петлю, чтобы сделать это. И, вероятно, потребуется несколько раз. Тем не менее, вы можете использовать структуру данных с разделителями, чтобы сделать ее довольно эффективной: https://en.wikipedia.org/wiki/Disjoint-set_data_structure –
Почему бы вам не показать вашу попытку с помощью циклов; это может стать хорошей отправной точкой для улучшения других на –