赞
踩
困难题,字典树或者ac自动机,注意是字符流,字符是一个个添加进来的,所以之前的状态也很重要,需要保存前一个字符匹配的结点,当前字符从这个结点开始匹配。
没有优化(实在写不下去了),基本就是模板思路。
数据结构与算法之美:36 | AC自动机:如何用多模式串匹配实现敏感词过滤功能
class StreamChecker { public: struct acNode{ bool isEnd = false; acNode* next[26] = {NULL}; acNode* fail = NULL; //失败指针 }; StreamChecker(vector<string>& words) : root(new acNode()){ for(const auto& word : words){ auto p = root; for(int i = 0; i < word.size(); ++i){ int idx = word[i] - 'a'; if(p->next[idx] == NULL) p->next[idx] = new acNode(); p = p->next[idx]; } p->isEnd = true; } buildFailPoint();//创建失败指针 beg = root; //检索的起始节点是root } void buildFailPoint(){ queue<acNode*> my_q;//BFS my_q.push(root); while(!my_q.empty()){//层次遍历,root在第一层 auto p = my_q.front();my_q.pop(); for(int i = 0; i < 26; ++i){ auto pc = p->next[i]; if(pc == NULL) continue;//不需要fail指针 if(p == root) pc->fail = root;//pc在第二层,fail指针只能指向root else{// auto q = p->fail; while(q != NULL && q->next[i] == NULL)//p的失败指针在对应字符位置没有值,说明没有匹配到该字符 q = q->fail;//再寻找q的失败指针 if(q == NULL) pc->fail = root;//q没有失败指针(默认即为NULL),就只能指向root else pc->fail = q->next[i]; } my_q.push(pc); } } } bool query(char letter) { int idx = letter - 'a'; while(beg != root && beg->next[idx] == NULL)//失配 beg = beg->fail;// 失败指针发挥作用的地方 beg = beg->next[idx]; if(beg == NULL) beg = root;// 没有匹配成功,从root开始重新匹配 else{ auto tmp = beg; while(tmp != root){ if(tmp->isEnd) return true; tmp = tmp->fail; } } return false; } private: acNode *root; acNode *beg; //检索的起始节点 };
另外这题是没有必要用ac自动机的,我这么用纯粹是自己想练一下手。这个题简单使用字典树或者哈希表或许也能解。
翻转单词并建立字典树(后缀树),常用技巧了,剩下的都是字典树典型操作了:
class StreamChecker { public: struct TrieNode{ bool isEnd = false; TrieNode* next[26] = {NULL}; }; StreamChecker(vector<string>& words) : root(new TrieNode()), s(""){ for(const auto& word : words){ auto p = root; for(int i = word.size()-1; i >= 0; --i){//逆序 int idx = word[i] - 'a'; if(p->next[idx] == NULL) p->next[idx] = new TrieNode(); p = p->next[idx]; } p->isEnd = true; } } bool query(char letter) { s += letter; auto p = root; for(int i = s.size()-1; i >= 0; --i){ int idx = s[i] - 'a'; if(p->next[idx] == NULL) return false; p = p->next[idx]; if(p->isEnd) return true; } return false; } private: TrieNode *root; string s; };
由于单词的最后一个字符可能是相同的,所以以最后一个字符建立哈希表的思路其实并不好,因为需要使用multimap,匹配的过程虽然思路直接,但是同key的元素过多的时候,还是需要一一对比,至少也需要二分查找。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。