joj 2734: keyword DFA 求字符串最多匹配多少字符串 每个子串最多匹配多少个 优化算法

本文介绍了一种高效的字符串关键字匹配算法,该算法能够处理大量的关键字,并在长文本中快速找到所有关键字出现的位置及次数。通过构建特殊的节点结构和使用队列进行广度优先搜索,实现了对关键字的高效查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出kkeyword,和一个字符串S.(仅大写字母)
求各个keyword出现的次数.
每个keyword在不同的位置出现即视为不同(可能出现重叠).

Input

MULTI TEST CASE!!
第一行,一个整数k(1<=k<=1000)
以下k,每行一个不同字符串表示keyword(|keyword|<=50)
最后一行一个字符串S(|S|<=10^6)

Output

按次序输出每个keyword匹配的次数,k
每行keyword 冒号 空格 出现的次数(0次也输出)

Sample Input

2
A
AB
BAAB

Sample Output

A: 2
AB: 1

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

#include<queue>

#include<cctype>

#include<map>

using namespace std;

const int maxn=80000;

struct Node

{

    int num;//序号

    int id;//在静态链表中的位置

    Node* next[27];

    Node* fail;

};

Node temp[maxn];

int tp;

int occ[maxn];

int n;

Node* root;

char mat[1100][55];

int cont[1100];

void reset(Node* p)

{

    p->num=0;p->id=tp-1;

    for(int i=0;i<27;i++) p->next[i]=NULL;

    p->fail=root;

    if(p==root) p->fail=NULL;

}

void init()

{

    memset(cont,0,sizeof(cont));

    tp=0;

    root=&temp[tp++];

    reset(root);

}

void insert(char* word,int index)

{

    Node* p=root;

    for(int i=0;word[i];i++)

    {

        int x;

        if(isupper(word[i])) x=word[i]-'A';

        else x=26;

        if(p->next[x]==NULL)

        {

            p->next[x]=&temp[tp++];

            reset(p->next[x]);

        }

        p=p->next[x];

    }

    p->num=index;

}

Node* que[maxn*4];

int front,rear;

void DFA()

{

    Node* p=root;

    front=rear=0;

    que[rear++]=p;

    while(front<rear)

    {

        Node* t=que[front++];

        for(int i=0;i<27;i++)

        {

            Node* cnt=t->next[i];

            if(cnt!=NULL)

            {

                Node* fath=t->fail;

                while(fath!=NULL&&fath->next[i]==NULL)

                {

                    fath=fath->fail;

                }

                if(fath!=NULL)

                {

                    cnt->fail=fath->next[i];

                }

                else

                {

                    cnt->fail=p;

                }

                que[rear++]=cnt;

            }

        }

    }

}

void find(char* str)

{

    memset(occ,0,sizeof(occ));

    Node* p=root;

    Node* fath;

    Node* cnt;

    for(int i=0;str[i];i++)

    {

        int x;

        if(isupper(str[i])) x=str[i]-'A';

        else x=26;

        cnt=p->next[x];

        if(cnt!=NULL)

        {

            occ[cnt->id]++;

//            for(fath=cnt;fath!=NULL;fath=fath->fail)

//            {

//                if(fath->num)

//                {

//                    cont[fath->num]++;

//                }

//            }

            p=cnt;

        }

        else

        {

            fath=p->fail;

            while(fath!=NULL&&fath->next[x]==NULL)

            {

                fath=fath->fail;

            }

            if(fath!=NULL)

            {

                cnt=fath->next[x];

                occ[cnt->id]++;

//                for(fath=cnt;fath!=NULL;fath=fath->fail)

//                {

//                    if(fath->num)

//                    {

//                        cont[fath->num]++;

//                    }

//                }

                p=cnt;

            }

            else

            {

                p=root;

            }

        }

    }

/*

//按照bfs逆序  优化

    for(int i=rear-1;i>=0;i--)

    {

    int index=que[i]->id;

    if(occ[index])

    {

    cnt=&temp[index];

    if(cnt->num) cont[cnt->num]+=occ[index];

    }

    if(cnt!=NULL) fath=cnt->fail;

    else continue;

    if(fath!=NULL) occ[fath->id]+=occ[index];

    }

*/

    for(int i=0;i<maxn;i++)

    {

        if(occ[i])

        {

            cnt=&temp[i];

            for(fath=cnt;fath!=NULL;fath=fath->fail)

            {

                if(fath->num)

                {

                    cont[fath->num]+=occ[i];

                }

            }

        }

    }

    //map会超时

//    map<Node* ,int >::iterator it;

//    for(it=q.begin();it!=q.end();it++)

//    {

//        Node* cnt=it->first;

//        int tmp=it->second;

//        for(fath=cnt;fath!=NULL;fath=fath->fail)

//        {

//            if(fath->num)

//            {

//                cont[fath->num]+=tmp;

//            }

//        }

//    }

}

char str[2000000];

int main()

{

    while(scanf("%d",&n)==1)

    {

        init();

        for(int i=1;i<=n;i++)

        {

            scanf("%s",mat[i]);

            memcpy(str,mat[i],sizeof(mat[i]));

            insert(str,i);

        }

        DFA();

        scanf("%s",str);

        find(str);

        for(int i=1;i<=n;i++)

        {

            printf("%s: %d/n",mat[i],cont[i]);

        }

    }

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值