获取与先前定义的字符串集匹配的字符串的所有前缀的有效结构

Posted

技术标签:

【中文标题】获取与先前定义的字符串集匹配的字符串的所有前缀的有效结构【英文标题】:Efficient structure to get all prefixes of a string that match a previously defined set of strings 【发布时间】:2017-05-30 12:59:46 【问题描述】:

假设我有一组前缀,例如 ["a", "ab", "ba", "aba", "bbb"]。

我还有一个单词列表。对于此列表中的每个单词,例如“abad”,我想有效地获取与前缀集中的单词匹配的该单词的所有前缀。在这个例子中,我想作为输出 ["a","ab", "aba"]。

我只想使用标准中的结构。

我正在考虑某种树形结构,但我想不出一种相对轻松地实现它的方法。

【问题讨论】:

trie 怎么样? 这将是标准正则表达式的完美案例 @Someprogrammerdude 如何仅使用 std 在几行代码中实现 trie? 【参考方案1】:

一个简单的实现是使用 std::unordered_set 的哈希表,然后将列表中每个单词的每个前缀与集合进行比较。

#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>

int main ()

    std::unordered_set<std::string> myPrefixes = "a", "ab", "ba", "aba", "bbb";

    std::vector<std::string> listOfWords;

    for (int i = 0; i < listOfWords.size(); i++) 
        std::vector<std::string> result;
        std::string word = listOfWords[i];
        for (int j = 0; j < word.length() - 1; j++) 
            if (myPrefixes.count(word.substr(0, word.length - j)) > 0) 
                result.push_back(word.substr(0, word.length - j);
            
        
        // print the result vector or do whatever with it
    
    return 0;

【讨论】:

谢谢!快速评论:您只需要搜索最大长度前缀或单词的最小长度【参考方案2】:
    将前缀存储在std::vector&lt;std::string&gt; std::sort()向量 对于每个感兴趣的单词,使用std::mismatch() 来查找它们不匹配的字符,如果所有前缀都匹配,那么你就有一个匹配 如果部分匹配,则中断

您不需要任何特殊的数据结构。它会很快,可能不如尝试那么快,它会起作用吗 - 很可能。它是否有效 - 可能 - 取决于前缀和单词。

【讨论】:

【参考方案3】:

这个答案通过使用 trie 来提高性能会增加一点复杂性,这可能非常巨大。假设 M 前缀词,每个词与搜索词的平均 N 字母一起,使用 set 的上述过程的复杂性需要 O(N^2) 时间来查找 N 字母词的前缀。 Trie 方法的初始预处理成本为 O(MN),可以将搜索降低到 O(N)。

有趣的是,Trie 构建部分(下面的 Node 结构和 insert 函数)实际上只需要 7 行。

struct Node

    bool is_Leaf = false;
    unordered_map<char,Node*> transitions;
;

void insert(Node* node,char* str,char* end)
    if(str==end) node->is_Leaf = true;return ;
    if (node->transitions[*str]==nullptr) node->transitions[*str] = new Node();
    insert(node->transitions[*str],str+1,end);


void search(Node* root,char* str,char* end,string so_far="")
    if(root && root->is_Leaf) cout<<so_far<<endl;
    if(!root or str==end) return;
    so_far.push_back(*str);
    search(root->transitions[*str],str+1,end,so_far); 


int main(int argc, char const *argv[])

    Node* root = new Node();
    vector<string> prefixes = "a", "ab", "ba", "aba", "bbb";
    for(auto& s:prefixes) insert(root,&s[0],&s[0]+s.size());

    string to_search = "abad";
    search(root,&to_search[0],&to_search[0]+to_search.size(),"");
    return 0;

【讨论】:

【参考方案4】:

我认为尝试是最快的方式。但我不知道是否有标准特里。 尝试一下,您检查前缀的速度非常快。

你的 trie 看起来像这样:

红色节点是endnodes......所以从顶部到红色节点是一个前缀。

如果你只能使用标准的东西,你可以写一个类节点。在这堂课中,您有一个 std::map 给孩子们。如果您的 trie 中有多个 a 和 b,则该地图将帮助您快速找到正确的子节点……如果您使用汉字或其他字母……(只有少数元素,您最好使用 std: :向量)

您还需要一种添加前缀的方法。 之后,您只需要一个方法来检查给定单词是否是前缀,方法是遍历节点和映射并检查我们是否通过了红色节点。

【讨论】:

【参考方案5】:

正如已经提到的,trie 是开始寻找的开始,一些Radix tree 可能是,但是有很多选项,但不幸的是,它们都没有在 std.xml 中明确显示。如果你想要一些快速实用的东西,我知道 this article 它是为 C# 描述的,但在 C++ 中很容易实现。

【讨论】:

以上是关于获取与先前定义的字符串集匹配的字符串的所有前缀的有效结构的主要内容,如果未能解决你的问题,请参考以下文章

暖*墟 #AC自动机# 多模式串的匹配运用

linux grep 正则表达式

如何实现最快的算法来匹配前缀与字符串?

51nod 1277字符串中的最大值(拓展kmp)

ES系列二十kibana基本用法

如何在与用户给定前缀匹配的字符串向量中找到第一个单词?