Algorithm 用于查询集合中是否存在给定子集的数据结构

Algorithm 用于查询集合中是否存在给定子集的数据结构,algorithm,data-structures,set,subset,multiset,Algorithm,Data Structures,Set,Subset,Multiset,我正在尝试为文字游戏解算器构建一个数据结构 我需要存储大约150000组{A,A,D,E,I,L,p,T,V,Y}的形式。(它们是标准化的英语单词,即已排序的字符。请注意,这是一个多集,可以包含相同的字母两次。) 需要有效地获得以下类型查询的是/否答案:是否存在具有给定子集的集合?例如,是否有任何已知单词包含集合{D,E,I,L,L,P} 要求: 查询必须快速 数据结构应该适合一个合理的空间量(例如,您可以使用一个trie并将每个集合插入到trie中,使用您的目标子集迭代遍历trie以确定是否

我正在尝试为文字游戏解算器构建一个数据结构

我需要存储大约150000组{A,A,D,E,I,L,p,T,V,Y}的形式。(它们是标准化的英语单词,即已排序的字符。请注意,这是一个多集,可以包含相同的字母两次。)

需要有效地获得以下类型查询的是/否答案:是否存在具有给定子集的集合?例如,是否有任何已知单词包含集合{D,E,I,L,L,P}

要求:

  • 查询必须快速

  • 数据结构应该适合一个合理的空间量(例如,您可以使用一个trie并将每个集合插入到trie中,使用您的目标子集迭代遍历trie以确定是否有匹配的子集。至少我认为我会这样做

    “trie”实际上是为一种可检索的数据结构而设计的,与普通树非常相似,但具有不同排列的节点,例如:

         A
        / \
       AT AN
         / | \
        |  |  AND
       ANN ANY
        |
      ANNA
    
    在上面的示例中,您可以看到这可能对您的情况很有用,因为可以像一个集合一样检索ANN和ANNA。您可能需要使用一些排列代码,以及这种类型的ADT(抽象数据类型)


    “查找更多”

    看起来您可以尝试使用或变体

    需要探讨的一个相关主题是多维范围搜索/查询

    注意:我自己没有用过这些,但我希望你能通过阅读一些关于上述主题的文献找到一些有用的东西


    希望这能有所帮助。

    这让我想起了我曾经做过的一个变异前缀树/trie。虽然略有不同,但它可能会起作用。如果您有很大的/没有边界,或者无法将其转换为您的语言(我用c++编写代码),它可能不会起作用

    基本上,在trie中,你通常存储下一个字母对应的子元素,但我所做的是存储每个字母频率对应的子元素

    从我的观点来看,问题基本上是,“是否有任何集合的字母数与子集中的字母数相同或更多?”例如,如果子集是{a,D,E,E},那么你需要找出是否有一个集合至少有一个a,一个D和两个E

    所以,对于trie,你有这样的东西

                Root
               / | \
              / /|\ \
             / / | \ \
            1 2  ... MAX <-- This represents the frequency of "A"
           /|\ ..... /|\
          1..MAX    1..MAX <-- Frequency of "B"
          ...............
          ...............
          ...............
         1 ... ... ... MAX <-- Frequency of "Y"
        /|\ .... .... / | \
       1..MAX ...... 1 .. MAX <-- Frequency of "Z"
    
    创建节点时,需要将其所有子节点初始化为NULL

    NODE* makeNode() {
        NODE* n = new NODE;         // Create a NODE
        for(int i = 0;i <= MAX;i++) // For each child
            n->child[i] = NULL;     // Initialize to NULL
    };
    
    将集合添加到trie时,将获得每个字母的频率并遍历trie。如果在特定节点上,下一个字母对应的子节点为NULL,则只需创建一个新节点

    搜索trie时,搜索与子集中字母频率或更大字母频率对应的每个节点的所有子节点。例如,如果子集有3个A,则搜索所有根->子节点[3],然后搜索根->子节点[4],然后…然后搜索根->子节点[MAX]


    这可能过于复杂和令人困惑,因此1)如果你认为我没有生气,那么请评论什么是令人困惑的,2)你可能/可能想找到一个更简单的方法

    听起来你需要查找字谜软件的例子。有趣的是,你应该提到这一点;这是一种字谜;然而,我需要找到“近字谜”或部分字谜。i、 e.我需要通过重新排列和添加给定池中的字母来查找字谜。如果我正确理解了建议,我的想法是将每个多字母集视为26个元素的向量。子集查询对应于正交范围查询。进行了一些搜索,它听起来像一个26-D范围树,这正是我需要的,但它的实现太复杂了@大卫:我猜一定有现成的解决方案。当然,我自己也没试过找,不用麻烦了。26维kd树的最坏情况查询时间是O(n^(1-1/26)),这基本上是线性的。维基百科的文章建议,实际上,N(150000)应该比2^k(2^26)大很多≈ 64000000)。@David:你可以合并维度。比如说合并A和B、C和D等。一旦你得到缩减的候选列表,你会进行线性搜索/查找不同的多维结构等。基本上,将这种方法与不同的方法结合起来,以便在空间和时间之间进行权衡。如果没有实际的数据和访问模式,最好的方法是建议可能有用的一般结构。您所问的似乎与范围查询有着非常密切的联系,实际上我希望看到一个更有效的解决方案!我考虑过trie,但这种直接的方法实际上不起作用。用一个“单词”来考虑这个词,“AANN”。然后,我们查找“ANN”,看看它是否在trie中,而不是。我以前确实尝试过这种技术,使用了DAWG(有向无环单词图)之类的东西,为每个有效集添加了多条路径,但其大小非常大。主要的困难在于,对于长度为m的子集,有O(m!)种方法可以达到目的——以不同的顺序添加字符。我刚刚实现了这一点,它的构建速度非常快,并且节省了大量空间(对于180k个字,大约6MB)。它也适用于许多查询。然而,不幸的是,有些退化查询只需要遍历许多分支。也许一种优化方法是按照树的最大数量对树的级别进行重新排序,从而最小化所需的回溯量。非常有趣!我想知道当您搜索类似“给我所有
    [A,Y]
    的超集”这样的内容时,这将如何工作?
    NODE* makeNode() {
        NODE* n = new NODE;         // Create a NODE
        for(int i = 0;i <= MAX;i++) // For each child
            n->child[i] = NULL;     // Initialize to NULL
    };
    
    NODE* root = new NODE;