字典樹Trie的簡單題目
阿新 • • 發佈:2019-01-23
題意:給N個模式串,每個不超過個字元,再給M個句子,句子長度< 100 判斷每個句子裡是否包含模式串 N < 10, M < 10 ,字元都是小寫字母
5 8
abcde
defg
cdke
ab
abcdkef
abkef
bcd
bca
add
ab
qab
f
#include<iostream>
using namespace std;
#include<vector>
#include<queue>
#define letters 26
#include<cstring>
int nNodesCount=0;
struct CNode
{
CNode *pChilds[letters];
CNode *pPrev; //字首指標
bool bBadNode; //檢視是否是危險節點
void Init()
{
memset(pChilds,0,sizeof(pChilds));
bBadNode=false;
pPrev=NULL;
}
};
CNode Tree[200]; //10個模式串,每個10個字元,每個字元一個節點, 也只要100個節點
void Insert(CNode *pRoot,char *s)
{
//將模式串s插入trie樹
for (int i=0;s[i];i++)
{
if (pRoot->pChilds[s[i]-'a']==NULL)
{
pRoot->pChilds[s[i]-'a']=Tree+nNodesCount;
nNodesCount++;
}
pRoot=pRoot-pChilds[s[i]-'a'];
}
pRoot->bBadNode=true;
}
void BuildDfa()
{
//在trie樹上加字首指標
for (int i=0;i<letters;i++)
Tree[0]->pChilds[i]=Tree+1;
Tree[0].pPrev=NULL;
Tree[1].pPrev=Tree;
deque<CNode *>q;
q.push_back(Tree+1);
while (!q.empty())
{
CNode *pRoot=q.front();
q.pop_front();
for (int i=0;i<letters;i++)
{
CNode *p=pRoot->pChilds[i];
if (p)
{
CNode *pPrev=pRoot->pPrev;
while (pPrev)
{
if (pPrev->pChilds[i])
{
p->pPrev=pPrev->pChilds[i];
if (p->pPrev->bBadNode)
p->bBadNode=true; //自己的pPrev指向的節點是危險節點 則自己也是危險節點
break;
}
else
pPrev=pPrev->pPrev;
}
q.push_back(p);
}
}
}
}
bool SearchDfa(char *s)
{
//返回值為true則說明包含模式串
CNode *p=Tree+1;
for (int i=0;s[i];i++)
{
while (true)
{
if (p->pChilds[s[i]-'a'])
{
p=p->pChilds[s[i]-'a'];
if (p->bBadNode)
return true;
break;
}
else
p=p->pPrev;
}
}
}
int main()
{
nNodesCount=2;
int M,N;
cin>>N>>M;
for (int i=0;i<N;i++)
{
char s[20];
cin>>s;
Insert(Tree+1,s);
}
BuildDfa();
for (int i=0;i<M;i++)
{
char s[200];
cin>>s;
cout<<SearchDfa(s)<<endl;
}
return 0;
}