【问题标题】:Find the intersection between sublists查找子列表之间的交集
【发布时间】:2015-03-06 11:28:03
【问题描述】:

最近我遇到了一个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 或者只是修改我的功能并让它变得更好? .如果您有任何建议,我将不胜感激!

【问题讨论】:

    标签: python list numpy data-structures intersection


    【解决方案1】:

    这是一个更有效的算法:

    1. 对于存在于至少一个子列表中的每个唯一编号,让我们维护一个包含该编号的所有子列表的索引列表。这部分是O(n * log n)时间,如果我们使用排序来查找唯一数字或O(n),如果我们使用哈希表,其中n是所有子列表中元素的总数。

    2. 让我们创建一个图,其中顶点是子列表索引,如果两个索引一起出现在所有数字中的至少一个索引列表中,则存在一条边。我们最多需要创建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])
      
    3. 现在我们可以使用线性时间的深度优先搜索在该图中找到连通分量(该图是无向的)。

    4. 我们知道应该合并哪些子列表(当且仅当它们在同一个连通组件中时才应该合并),因此我们可以轻松构造答案。

    总时间复杂度为O(n)。这是最优的,因为读取输入已经需要O(n) 操作。

    【讨论】:

    • 这还不错,但我认为你没有很好地理解我的代码,我使用集合来检查成员资格,因为它的 O(1) 并且我使用 2 而不是 O(n^2) 是因为内部列表和主列表的长度在任何循环后都会减少。
    • @Kasra 你的代码至少是O(n^2)(也许更多)。例如,如果所有子列表只包含一个元素并且只有最后两个相交,则将进行 n * (n - 1) / 2 次迭代。
    • 你让我怀疑。有点。
    • @Kasra 试试这个测试用例:[[1], [2], ..., [n - 2], [n], [n]]。毫无疑问,您的解决方案会对其进行O(n ^ 2) 操作。
    • 加 1 。我必须说我知道这一点,但我有一个错误的理解。所以这是最坏的情况!由于您的解决方案是一个很好的算法解决方案,我需要等待 pythonic 建议
    【解决方案2】:
    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
    

    【讨论】:

    • 如果您能解释一下代码适用于解决 OP 问题的内容和原因,我会很有帮助。
    猜你喜欢
    • 2021-03-18
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多