有效地从一组列表中查找重叠段

时间:2014-04-28 23:11:28

标签: algorithm list

假设我有以下列表:

[1, 2, 3, 20, 23, 24, 25, 32, 31, 30, 29] [1, 2, 3, 20, 23, 28, 29] [1, 2, 3, 20, 21, 22] [1, 2, 3, 14, 15, 16] [16, 17, 18] [16, 17, 18, 19, 20]

订单在这里很重要。这些是由加权图中的深度优先搜索产生的节点。我想要做的是将列表分解为唯一路径(路径至少有2个元素)。因此,上面的列表将返回以下内容:

[1, 2, 3] [20, 23] [24, 25, 32, 31, 30, 29] [28, 29] [20, 21, 22] [14, 15, 16] [16, 17, 18] [19, 20]

我现在的一般想法是:

  1. 查看所有列表对,在列表开头创建一组重叠段列表。例如,在上面的例子中,这将是输出:
    [1, 2, 3, 20, 23] [1, 2, 3, 20] [1, 2, 3] [16, 17, 18]

  2. 下一个输出是这样的:
    [1, 2, 3] [16, 17, 18]

  3. 一旦我获得了步骤2中的列表,我会查看每个输入列表,如果它与步骤2中的一个列表匹配,则会切断前面的列表。新列表如下所示:
    [20, 23, 24, 25, 32, 31, 30, 29] [20, 23, 28, 29] [20, 21, 22] [14, 15, 16] [19, 20]

  4. 然后我返回并将步骤1应用于步骤3中的截断列表。当步骤1未输出任何重叠列表时,我已完成。

  5. 第2步是这里棘手的部分。愚蠢的是它实际上等同于解决原始问题,尽管在较小的列表上。

    解决此问题的最有效方法是什么?查看所有对显然需要O(N ^ 2)时间,并且步骤2看起来很浪费,因为我需要运行相同的过程来解决这些较小的列表。我试图弄清楚是否有更聪明的方法来做到这一点,而且我被卡住了。

2 个答案:

答案 0 :(得分:1)

似乎解决方案是修改Trie以达到目的。 Trie压缩提供了线索,但这里所需的压缩类型不会产生任何性能优势。

您添加的第一个列表将成为它自己的节点(而不是k个节点)。如果有任何重叠,节点会分裂,但永远不会小于保持数组的两个元素。

图结构的一个简单示例如下所示:

insert (1,2,3,4,5)
graph: (1,2,3,4,5)->None
insert (1,2,3)
graph: (1,2,3)->(4,5), (4,5)->None
insert (3,2,3)
graph: (1,2,3)->(4,5), (4,5)->None, (3,32)->None
segments
output: (1,2,3), (4,5), (3,32)

子节点也应该作为一个实际的Trie添加,至少当它们足够多时,为了避免在数据结构中添加/删除时的线性搜索,并可能将运行时间增加N倍。如果是实现后,数据结构具有与Trie相同的大O性能,隐藏常数稍高。这意味着它需要O(L * N),其中L是列表的平均大小,N是列表的数量。获得段是段数的线性。

对于您的示例,最终的数据结构(基本上是有向图)如下所示,起始节点位于底部。

请注意,此数据结构可以在运行DFS而不是后缀时构建。

Prefix Compressed Trie

答案 1 :(得分:0)

我最后通过略微区别地思考问题来解决这个问题。我没有考虑节点序列(每个连续节点对之间隐含边缘),而是考虑边缘序列。我基本上使用我最初发布的算法。步骤2只是一个迭代步骤,我重复识别前缀,直到没有剩余的前缀来识别。这很快,处理边缘而不是节点真的简化了一切。

感谢大家的帮助!