您可以使用数据结构来提高执行合并的效率。在这里,您创建了某种相反的树。因此,在您的示例中,您首先将创建列出的数字:
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)
and(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
并为映射到 a的每个元素创建一个字典Merge
:
dic = {val:Merge(val) for val in vals}
和merge_heads
:
merge_heads = set(dic.values())
现在对于数组中的每个元组,我们查找作为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
in构造一个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(n 2 )中运行最坏的情况,但您可以平衡树,以便在O(log n)中找到祖先,使其成为O(n log n)。此外,您可以 缩短祖先列表,使其更快。