Algorithm 超集搜索

Algorithm 超集搜索,algorithm,language-agnostic,data-structures,indexing,set,Algorithm,Language Agnostic,Data Structures,Indexing,Set,我正在寻找一种算法,在合理的时间内解决以下问题 给定一组集合,查找作为给定集合子集的所有此类集合。 例如,如果您有一组搜索词,如[“堆栈溢出”、“foo-bar”、…],那么给定一个文档D,查找其单词全部出现在D中的所有搜索词 我找到了两个足够的解决方案: 使用位向量列表作为索引。要查询给定的超集,请为其创建位向量,然后在列表上迭代,对列表中的每个向量执行按位OR。如果结果等于搜索向量,则搜索集是由当前向量表示的集的超集。这个算法是O(n),其中n是索引中的集合数,按位OR非常快。插入是O(1)

我正在寻找一种算法,在合理的时间内解决以下问题

给定一组集合,查找作为给定集合子集的所有此类集合。

例如,如果您有一组搜索词,如[“堆栈溢出”、“foo-bar”、…],那么给定一个文档D,查找其单词全部出现在D中的所有搜索词

我找到了两个足够的解决方案:

  • 使用位向量列表作为索引。要查询给定的超集,请为其创建位向量,然后在列表上迭代,对列表中的每个向量执行按位OR。如果结果等于搜索向量,则搜索集是由当前向量表示的集的超集。这个算法是
    O(n)
    ,其中n是索引中的集合数,按位OR非常快。插入是
    O(1)
    。警告:为了支持英语语言中的所有单词,位向量将需要几百万位长,并且需要存在单词的总顺序,没有间隙

  • 使用前缀树(trie)。在将集合插入trie之前对其进行排序。搜索给定集合时,请先对其排序。迭代搜索集的元素,激活匹配的节点(如果它们是根节点的子节点或以前激活的节点的子节点)。通过激活节点到叶的所有路径表示搜索集的子集。该算法的复杂度为
    O(a log a+ab)
    ,其中
    a
    是搜索集的大小,
    b
    是索引集的数量


  • 你的解决方案是什么?

    如果集合相对于总词汇表来说比较稀疏,那么前缀trie听起来像是我会尝试的。不要忘记,如果两个不同前缀的后缀集相同,则可以共享表示后缀集的子图(这可以通过哈希考虑而不是任意DFA最小化来实现),从而得到DAG而不是树。试着先把你的单词排列得最少或最频繁(我打赌其中一个比随机或字母顺序要好)

    对于第一种策略的变体,即用一个非常大的整数(位向量)表示每个集合,请使用稀疏有序的整数集/整数映射(位序列上的trie,跳过连续0的运行)-(在中实现)


    如果你的参考集合(集合)是固定的,并且你想找出其中许多集合包含其他集合,我会计算直接包含关系(a中包含有a->b iff b路径的有向无环图,没有冗余弧a->c,其中a->b和b->c)。分支因子不超过集合中的元素数。从给定集合可以到达的顶点正是它的子集。

    首先,我将构造两个数据结构,S和E

    S是集合的数组(集合S有N个子集)


    E是列表的映射(索引的元素哈希)。每个列表都包含元素出现的S索引

    // O( S_total_elements ) = O(n) operation
    E[element1] = list(S1, S6, ...)
    E[element2] = list(S3, S4, S8, ...)
    ...
    

    现在,两个新结构,集合L和数组C。

    我将存在于E中的D的所有元素存储在L.(O(n)操作中)
    C是计数器的数组(S索引)。

    最后,

    for i in C:
        if C[i] == S[i].Count()
           // S[i] subset exists in D
    

    你能为你的文档建立索引吗?i、 从每个单词到包含该单词的文档的映射。一旦你建立了它,查找应该是相当快的,你只需设置交集就可以找到匹配所有单词的文档

    这里是维基

    编辑:好的,我倒过来了

    您可以将文档转换为集合(如果您的语言具有集合数据类型),也可以对搜索执行相同的操作。然后,测试其中一个是否是另一个的子集就变得很简单了


    在幕后,这实际上是相同的想法:它可能涉及为文档构建一个哈希表,对查询进行哈希运算,然后依次检查查询中的每个单词。这将是O(nm),其中n是搜索的数量,m是搜索中的平均字数。

    是否对集合下单?换句话说,集合{a,b}与集合{b,a}相同吗?还有(2)项?您在第一行中实际排序的是什么?似乎你必须先解决问题,然后应用你的算法。(虽然我可能误解了)。您是否关心多集?文档(“给定集”)能否包含同一元素的多个实例?一个搜索集(集合的成员)怎么样?也就是说,如果文档中说“我不会读我已经读过的书”,搜索“read read book”会匹配,但“read read book”不会匹配。不,根本不涉及多集。第二种方法对我解决类似问题非常有效。我用trie将Naiver方法的14小时执行时间减少到2分钟(!),我正在做相反的事情。给定一百万个搜索和一个文档,查找与给定方法的文档匹配的所有搜索。
    // count subset's elements that are in E
    foreach e in L:
      foreach idx in E[e]:
          C[idx] = C[idx] + 1
    
    for i in C:
        if C[i] == S[i].Count()
           // S[i] subset exists in D