最近我遇到一个question关于查找子列表之间的交集。告诉子列表哪个(1个或多个)交叉点合在一起。例如以下列表:
l=[[1,2,3],[0,13,6],[9,10],[3,4,5],[10,11],[6,7,50]]
必须转换为:
[[1, 2, 3, 4, 5],[0, 50, 6, 7, 13],[9, 10, 11]]
所以我编写了以下函数,以便在性能良好的情况下运行良好,我使用set
来检查成员资格的快速复杂性,并且在内部循环中我使用切片来比较主列表的第一个索引在每个循环中使用其他元素,并注意每个循环后列表将减少,因为它是循环内的递归。 :
s=[set(i) for i in g if i]
def find_intersection(m_list):
for i,v in enumerate(m_list) :
for j,k in enumerate(m_list[i+1:],i+1):
if v & k:
s[i]=v.union(m_list.pop(j))
return find_intersection(m_list)
return m_list
s=[set(i) for i in l if i]
print find_intersection(s)
[set([1, 2, 3, 4, 5]), set([0, 50, 6, 7, 13]), set([9, 10, 11])]
但我认为可以通过另一种解决方案来完成,可能性能更好,我考虑collections.deque
或者numpy
或者只是修改我的功能并使其更好? 。如果您有任何建议,我将不胜感激!
答案 0 :(得分:4)
这是一种更有效的算法:
对于至少一个子列表中存在的每个唯一编号,让我们维护包含此编号的所有子列表的索引列表。如果我们使用排序来查找唯一数字,则此部分为O(n * log n)
时间;如果我们使用哈希表,则O(n)
使用n
,其中O(n)
是所有子列表中元素的总数。
让我们创建一个图表,其中顶点是子列表索引,如果两个索引一起出现在所有数字中的至少一个索引列表中,则存在边缘。我们需要创建最多g = empty graph
for elem in unique_elements:
sublist_indices = list of indices of all sublists that contain this element
for i = 1 ... size(sublist_indices - 1):
g.add_edge(sublist_indices[i], sublist_indices[i + 1])
个边缘(这部分有点不重要:不需要显式创建所有边缘,我们可以在每个子列表中为所有唯一元素添加边缘从元素到下一个边缘由于传递性)。这是一些伪代码:
O(n)
现在我们可以在线性时间内使用深度优先搜索找到此图表中的连通分量(此图表是无向的)。
我们知道哪些子列表应该合并(当且仅当它们在同一个连接组件中时才应合并),这样我们就可以轻松构建答案。
总时间复杂度为O(n)
。这是最佳选择,因为阅读输入已经需要{{1}}次操作。
答案 1 :(得分:0)
l=[[1,2,3],[0,13,6],[9,10],[3,4,5],[10,11],[6,7,50]]
temp = []
result = []
for i in range(len(l)):
for j in range(i + 1, len(l)):
if set(l[i]).intersection(l[j]):
temp.append(l[i] + l[j])
result.append(list(set(temp[i])))
print result