先要了解 字符串多模匹配 到底能做什么
首先 先给你q 个查询串 ,再给你一个主串s (或者很多个不同主串)
可以做什么?
- q个查询串 有几个 在主串里 匹配成功了 可以记个cnt统计(查询串不重复,重复的要计算数量的话,要加个sum记录 重复查询串 出现了几次)
- 还可以知道 匹配成功 的查询串是哪些(偷懒还用 sum标 它是第几个查询串)
字典树就不用说了吧,建字典树还是很好理解的
失配指针:
我们用fail表示当前字符的失配指针,它代表的含义就是——以当前字符为结尾的最长后缀 的位置。
最后就是把主串放在字典树里匹配,这个过程也好理解
假设先匹配成功了一小段,那么找下一个字母,匹配成功的这一段的最后一个 的下一个字符。
贴上代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 1e4 + 200;
const int Inf = 1e9 + 7;
const int MAX = 1e7;
int cnt , N;
struct node{
node *next[26];
node *fail;
int sum;
};
node *root , *q[MAX] , *newnode;
char key[210];
char pattern[Maxn];
int head,tail;
void Insert(char *s)
{
node *p = root;
for(int i = 0; s[i]; i++)
{
int x = s[i] - 'a';
if(p->next[x] == NULL)
{
newnode = new node;
for(int j=0;j<26;j++) newnode->next[j] = 0;
newnode->sum = 0;newnode->fail = 0;
p->next[x]=newnode;
}
p = p->next[x];
}
p->sum++;
}
void build_fail_pointer()
{
head = 0;
tail = 1;
q[head] = root;
node *p;
node *temp;
while(head < tail)
{
temp = q[head++];
for(int i = 0; i <= 25; i++)
{
if(temp->next[i])
{
if(temp == root)
{
temp->next[i]->fail = root;
}
else
{
p = temp->fail;
while(p)
{
if(p->next[i])
{
temp->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if(p == NULL) temp->next[i]->fail = root;
}
q[tail++] = temp->next[i];
}
}
}
}
void ac_automation(char *ch)
{
node *p = root;
int len = strlen(ch);
for(int i = 0; i < len; i++)
{
int x = ch[i] - 'a';
while(!p->next[x] && p != root) p = p->fail;
p = p->next[x];
if(!p) p = root;
node *temp = p;
while(temp != root)
{
if(temp->sum >= 0)
{
cnt += temp->sum;
temp->sum = -1;
}
else break;
temp = temp->fail;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
root = new node;
for(int j=0;j<26;j++) root->next[j] = 0;
root->fail = 0;
root->sum = 0;
scanf("%d",&N);
getchar();
for(int i = 1; i <= N; i++)
{
gets(key);
Insert(key);
}
gets(pattern);
cnt = 0;
build_fail_pointer();
ac_automation(pattern);
printf("%d\n",cnt);
}
return 0;
}
感觉代码还能更好看一点
//HDU 2896
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define PrintString(ss) printf("%s\n",ss);
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 1e4 + 200;
const int Inf = 1e9 + 7;
const int over = 130;
int cnt , N;
struct node{
node *next[over];
node *fail;
int sum;
node(){
//memset(next , NULL , sizeof(next) );
for(int i = 0 ; i < over ; i++){
next[i] = NULL;
}
fail = NULL;
sum = 0;
}
};
node *root , *newnode;
char key[210];
char pattern[Maxn];
int head,tail;
void Insert(char *s , int num) {
node *p = root;
for(int i = 0; s[i]; i++) {
//int x = s[i] - 'a';
int x = s[i];
if(p->next[x] == NULL) {
newnode = new node;
p->next[x]=newnode;
}
p = p->next[x];
}
p->sum = num;
}
queue <node *> q;
void build_fail_pointer() {
q.push(root);
node *p;
node *temp;
while(!q.empty()) {
temp = q.front(); q.pop();
for(int i = 0; i < over; i++) {
if(temp->next[i]) {
if(temp == root) {
temp->next[i]->fail = root;
} else {
p = temp->fail;
while(p) {
if(p->next[i]) {
temp->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if(p == NULL) temp->next[i]->fail = root;
}
q.push(temp->next[i]);
}
}
}
}
vector <int> ans;
void ac_automation(char *ch)
{
node *p = root;
int len = strlen(ch);
for(int i = 0; i < len; i++) {
//int x = ch[i] - 'a';
int x = ch[i];
while(!p->next[x] && p != root) p = p->fail;
p = p->next[x];
if(!p) p = root;
node *temp = p;
while(temp != root) {
if(temp->sum > 0) { // 条件更改处
ans.push_back(temp->sum);
//cnt += temp->sum;
//temp->sum = -1;
}
else break;
temp = temp->fail;
}
}
}
int main()
{
root = new node;
scanf("%d",&N);
for(int i = 1; i <= N; i++) {
scanf(" %[^\n]",&key);
//PrintString(key);
Insert(key , i);
}
build_fail_pointer();
int Q; scanf(" %d",&Q);
cnt = 0;
for(int i = 1 ; i <= Q ; i++){
scanf(" %[^\n]",&pattern);
//PrintString(pattern);
ans.clear();
ac_automation(pattern);
if(ans.size()){
sort(ans.begin() , ans.end());
cnt++;
printf("web %d:",i);
for(int i = 0 ; i < ans.size() ; i++){
printf(" %d",ans[i]);
}
printf("\n");
}
}
printf("total: %d\n",cnt);
return 0;
}