字符串模板

KMP算法

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+7;
int next[maxn];
string s,t;
void get_next(string str){
    memset(next,0,sizeof(next));
    for(size_t i=1,j=0;i<str.size();i++){
        while(j>0&&str[i]!=str[j])
            j=next[j-1];
        if(str[j]==str[i])
            j++;
        next[i]=j;
    }
}
void kmp(){
    for(size_t i=0,j=0;i<s.size();i++){
        while(j>0&&s[i]!=t[j])
            j=next[j-1];
        if(s[i]==t[j])
            j++;
        if(j==t.size())
            printf("%d\n",i-j+1);
    }
}
int main(){
    ios::sync_with_stdio(false);
    getline(cin,s);
    getline(cin,t);
    get_next(t);
    kmp();
}

哈希

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const ull mag=1e4+7;
const int maxn=1e5+7;
ull magic[maxn],hs[maxn],ht[maxn];
void get_mag(int n){
    magic[0]=1;
    for(int i=1;i<=n;i++)
        magic[i]=magic[i-1]*mag;
}
void get_hash(string s,ull h[]){
    h[0]=s[0];
    for(int i=1;i<s.size();i++)
        h[i]=h[i-1]*mag+s[i];
}
ull get_int(int l,int r,ull h[]){
    if(l==0) return h[r];
    return h[r]-h[l-1]*magic[r-l+1];
}
int main(){
    ios::sync_with_stdio(false);
    string s,t;
    cin>>s>>t;
    int sz=s.size()-t.size();
    get_mag(max(s.size(),t.size()));
    get_hash(s,hs);
    get_hash(t,ht);
    for(int i=0;i<=sz;i++)
        if(get_int(i,i+t.size()-1,hs)==ht[t.size()-1])
            printf("%d\n",i);
}

AC自动机(有点复杂)

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int alp = 26;
const int maxn=5e5+7;
int head,tail;
char keyword[51];
char str[maxn*2];
struct node{
    node *fail;//失败指针
    node *next[alp];//儿子指针
    int count;
    node(){//构造函数
        fail=NULL;
        count=0;
        memset(next,NULL,sizeof(next));
    }
}*q[maxn];
void insert(char *str,node *root){//构建数,输入单词和根
    node*p=root; //从根开始
    for(int i=0,index;str[i];i++){//单词还没结束的时候
        index=str[i]-'a';
        node **tmp=&(p->next[index]);//把tmp作为p的这个字母的儿子的指针
        if(*tmp==NULL)//如果这个儿子本不存在
            *tmp=new node();//就增加一个
        p=*tmp;//把p作为他的这个儿子
    }
    p->count++;//到了单词的末尾了,标记末尾
}
void bfail(node *root){//构建失败指针
    root->fail=NULL;//把根节点的失败指针改为0
    q[head++]=root;//把根放入队列中
    while(head!=tail){//当队列不为空时
        node *temp=q[tail++];//拿出一个
        node *p=NULL;//建造空指针
        for(int i=0;i<alp;i++)//对于每个字母
            if(temp->next[i]!=NULL){//如果还有儿子
                if(temp==root)//如果这个就是根
                    temp->next[i]->fail=root;//把当前的儿子的失败指针设为根
                else{//不然的话
                    p=temp->fail;//把p设置为当前的失败指针
                    while(p!=NULL){//当p还存在时
                        if(p->next[i]!=NULL){//如果p有同样字母的儿子
                            temp->next[i]->fail=p->next[i];//那么当前的儿子的失败指针改为当前的失败指针指向的节点的儿子
                            break;//结束
                        }
                        p=p->fail;//如果没找到,就沿着失败指针继续找
                    }
                    if(p==NULL)//如果找不到了,就把它的这个儿子的失败指针指向root
                        temp->next[i]->fail=root;
                }
                q[head++]=temp->next[i];//将这个点放入队列
            }
    }
}
int query(node *root,char str[]){
    int cnt=0;//初始化答案
    node *p=root;//指向根
    for(int i=0;str[i];i++){//字符串还没结束
        index=str[i]-'a';
        while(p->next[index]==NULL&&p!=root)//如果为空,且p不是根
            p=p->fail;//找失败指针所指位置
        p=p->next[index];//p是根或者p的儿子存在时,变成它的儿子
        p=(p==NULL)?root:p;//只有当p是根时他的儿子为NULL,所以如果为根时继续为根,
        node *tmp=p;
        while(tmp!=root&&tmp->count!=-1){//tmp不是根且tmp的count不是-1
            cnt+=temp->count;//cnt加上count
            tmp->count=-1;//tmp的count改为-1,表示已经加过了
            tmp=tmp->fail;//tmp改为tmp的fail指针
        }
    }
    return cnt;//返回答案
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值